detached c117990

fix(web): MR description as Markdown, latest tag row inline, no install button (#60)

commit
c1179903253ff4075db07b94eb163628bc5d2851
author
brice · · 2026-10-18 09:06 UTC
committer
bnema · · 2026-10-18 09:06 UTC
parent
ef38ad0
signature
SSH UnverifiedSHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivA The key is unknown
46 files · +491 -695
M internal/adapters/web/ASSETS.md +1 -1
@@ -16,7 +16,7 @@ content-hashed names. Nothing is fetched at runtime.
1616 | `static/css/*.css` | native CSS, served as one stylesheet in name order; relative `url(fonts/…)` and `url(icons/…)` become hashed URLs | written here | |
1717 | `static/fonts/atkinson-next.woff2`, `atkinson-next-italic.woff2` | Atkinson Hyperlegible Next, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-next.txt`) | Google Fonts | `18b2a1a39a2fa298b0ba5390aca68462669826c90925656f1c1f6796e0e1bbaf`, `4a5037bfaf6680f40147407407ec09fa42925774bde809a579283d27f9f08106` |
1818 | `static/fonts/atkinson-mono.woff2` | Atkinson Hyperlegible Mono, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-mono.txt`) | Google Fonts | `2706b1ee4f452e744ea91f7e4908cbde9c5d35521bf5ffffc71a382a2de89613` |
19-| `static/icons/*.svg` | interface icons, used as CSS masks; `brand.svg` is a grey picture shown as is. Only the icons in use are copied, one file each: `branch`, `search`, `tag`, `file`, `chevron`, `user`, `key`, `log-in`, `log-out`, `download` are Lucide 1.8 (`git-branch`, `search`, `tag`, `file-text`, `chevron-down`, `user-round`, `key-round`, `log-in`, `log-out`, `download`; ISC, https://lucide.dev/license) | Lucide; `brand.svg` written here | |
19+| `static/icons/*.svg` | interface icons, used as CSS masks; `brand.svg` is a grey picture shown as is. Only the icons in use are copied, one file each: `branch`, `search`, `tag`, `file`, `chevron`, `user`, `key`, `log-in`, `log-out` are Lucide 1.8 (`git-branch`, `search`, `tag`, `file-text`, `chevron-down`, `user-round`, `key-round`, `log-in`, `log-out`; ISC, https://lucide.dev/license) | Lucide; `brand.svg` written here | |
2020 | `static/app/*.png` | icons of the installed web app (manifest, `apple-touch-icon`), rendered from `brand.svg` with resvg; the maskable and Apple icons have the picture in the safe zone on `#181818` | generated here | |
2121 | `static/sw.js` | the service worker of the installed app: a network-only passthrough (no cache), served at `/-/sw.js` with `Service-Worker-Allowed: /` and revalidated on each check (not a hashed asset) | written here | |
2222 | `static/rules.json` | speculation rules: prefetch the light same-origin pages on hover (`Speculation-Rules` header); the heavy ones (tree, blob, commit, commits, compare, refs, raw, MR "since") are excluded, each costs several Git reads on the server | written here | |
@@ -16,7 +16,7 @@ content-hashed names. Nothing is fetched at runtime.
16 | `static/css/*.css` | native CSS, served as one stylesheet in name order; relative `url(fonts/…)` and `url(icons/…)` become hashed URLs | written here | |16 | `static/css/*.css` | native CSS, served as one stylesheet in name order; relative `url(fonts/…)` and `url(icons/…)` become hashed URLs | written here | |
17 | `static/fonts/atkinson-next.woff2`, `atkinson-next-italic.woff2` | Atkinson Hyperlegible Next, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-next.txt`) | Google Fonts | `18b2a1a39a2fa298b0ba5390aca68462669826c90925656f1c1f6796e0e1bbaf`, `4a5037bfaf6680f40147407407ec09fa42925774bde809a579283d27f9f08106` |17 | `static/fonts/atkinson-next.woff2`, `atkinson-next-italic.woff2` | Atkinson Hyperlegible Next, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-next.txt`) | Google Fonts | `18b2a1a39a2fa298b0ba5390aca68462669826c90925656f1c1f6796e0e1bbaf`, `4a5037bfaf6680f40147407407ec09fa42925774bde809a579283d27f9f08106` |
18 | `static/fonts/atkinson-mono.woff2` | Atkinson Hyperlegible Mono, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-mono.txt`) | Google Fonts | `2706b1ee4f452e744ea91f7e4908cbde9c5d35521bf5ffffc71a382a2de89613` |18 | `static/fonts/atkinson-mono.woff2` | Atkinson Hyperlegible Mono, variable weight, latin subset (SIL OFL 1.1, `static/fonts/OFL-mono.txt`) | Google Fonts | `2706b1ee4f452e744ea91f7e4908cbde9c5d35521bf5ffffc71a382a2de89613` |
19-| `static/icons/*.svg` | interface icons, used as CSS masks; `brand.svg` is a grey picture shown as is. Only the icons in use are copied, one file each: `branch`, `search`, `tag`, `file`, `chevron`, `user`, `key`, `log-in`, `log-out`, `download` are Lucide 1.8 (`git-branch`, `search`, `tag`, `file-text`, `chevron-down`, `user-round`, `key-round`, `log-in`, `log-out`, `download`; ISC, https://lucide.dev/license) | Lucide; `brand.svg` written here | |19+| `static/icons/*.svg` | interface icons, used as CSS masks; `brand.svg` is a grey picture shown as is. Only the icons in use are copied, one file each: `branch`, `search`, `tag`, `file`, `chevron`, `user`, `key`, `log-in`, `log-out` are Lucide 1.8 (`git-branch`, `search`, `tag`, `file-text`, `chevron-down`, `user-round`, `key-round`, `log-in`, `log-out`; ISC, https://lucide.dev/license) | Lucide; `brand.svg` written here | |
20 | `static/app/*.png` | icons of the installed web app (manifest, `apple-touch-icon`), rendered from `brand.svg` with resvg; the maskable and Apple icons have the picture in the safe zone on `#181818` | generated here | |20 | `static/app/*.png` | icons of the installed web app (manifest, `apple-touch-icon`), rendered from `brand.svg` with resvg; the maskable and Apple icons have the picture in the safe zone on `#181818` | generated here | |
21 | `static/sw.js` | the service worker of the installed app: a network-only passthrough (no cache), served at `/-/sw.js` with `Service-Worker-Allowed: /` and revalidated on each check (not a hashed asset) | written here | |21 | `static/sw.js` | the service worker of the installed app: a network-only passthrough (no cache), served at `/-/sw.js` with `Service-Worker-Allowed: /` and revalidated on each check (not a hashed asset) | written here | |
22 | `static/rules.json` | speculation rules: prefetch the light same-origin pages on hover (`Speculation-Rules` header); the heavy ones (tree, blob, commit, commits, compare, refs, raw, MR "since") are excluded, each costs several Git reads on the server | written here | |22 | `static/rules.json` | speculation rules: prefetch the light same-origin pages on hover (`Speculation-Rules` header); the heavy ones (tree, blob, commit, commits, compare, refs, raw, MR "since") are excluded, each costs several Git reads on the server | written here | |
M internal/adapters/web/jstest/install.test.mjs +5 -71
@@ -1,22 +1,15 @@
11 // Tests of the install block of static/js/ermite.js (ermiteInstall): the
2-// service worker registration and the "install app" button. Run with
2+// service worker registration. Run with
33 // node --test 'internal/adapters/web/jstest/*.test.mjs'
44 import assert from 'node:assert/strict';
55 import { readFileSync } from 'node:fs';
66 import { test } from 'node:test';
7-import { dom, el, installDom } from './dom.mjs';
7+import { installDom } from './dom.mjs';
88
99 const doc = installDom();
10-const button = el('button', { attrs: { 'data-install': '' } });
11-button.hidden = true;
12-document.body.append(button);
13-
1410 const setNavigator = (v) => Object.defineProperty(globalThis, 'navigator', { value: v, configurable: true, writable: true });
1511 const listeners = {};
1612 globalThis.addEventListener = (type, fn) => { listeners[type] = fn; };
17-const fire = (type, ev) => listeners[type](ev);
18-let standalone = false;
19-globalThis.matchMedia = () => ({ matches: standalone });
2013 doc.readyState = 'loading';
2114 const registered = [];
2215 setNavigator({ serviceWorker: { register: async (url, opts) => { registered.push([url, opts]); return {}; } } });
@@ -25,17 +18,9 @@ setNavigator({ serviceWorker: { register: async (url, opts) => { registered.push
2518 const src = readFileSync(new URL('../static/js/ermite.js', import.meta.url), 'utf8');
2619 const start = src.indexOf(' window.ermiteInstall = ');
2720 const end = src.indexOf(' })();', start) + ' })();'.length;
28-new Function('$$', src.slice(start, end))((sel) => document.querySelectorAll(sel));
21+new Function(src.slice(start, end))();
2922 const I = window.ermiteInstall;
3023
31-// promptEvent is a beforeinstallprompt event.
32-function promptEvent(outcome = 'accepted') {
33- const e = { prevented: false, prompts: 0, preventDefault() { this.prevented = true; } };
34- e.prompt = async () => { e.prompts++; };
35- e.userChoice = Promise.resolve({ outcome });
36- return e;
37-}
38-
3924 test('the service worker is registered at the root scope once the page has loaded', async () => {
4025 assert.equal(registered.length, 0, 'not before load');
4126 await listeners.load();
@@ -49,57 +34,6 @@ test('a refused registration is not an error', async () => {
4934 assert.equal(await I.register(), null);
5035 });
5136
52-test('the button shows on beforeinstallprompt, and a click prompts once', async () => {
53- const e = promptEvent();
54- assert.equal(button.hidden, true);
55- fire('beforeinstallprompt', e);
56- assert.equal(e.prevented, true, 'the browser banner is replaced by the button');
57- assert.equal(button.hidden, false);
58- const done = listeners.click({ target: { closest: (s) => (s === '[data-install]' ? button : null) } });
59- assert.equal(done, undefined);
60- assert.equal(await I.pending, 'accepted');
61- assert.equal(await I.prompt(), '', 'the event was used by the click');
62- assert.equal(e.prompts, 1);
63- assert.equal(button.hidden, true);
64-});
65-
66-test('the button stays while the dialog is up; its focus then moves to the search', async () => {
67- const search = el('button', { attrs: { 'aria-controls': 'panel-cmd' } });
68- document.body.append(search);
69- const e = promptEvent('dismissed');
70- let shownDuring = null;
71- e.prompt = async () => { shownDuring = !button.hidden; };
72- fire('beforeinstallprompt', e);
73- button.focus();
74- dom.focused = [];
75- assert.equal(await I.prompt(), 'dismissed');
76- assert.equal(shownDuring, true, 'not hidden under the dialog');
77- assert.equal(button.hidden, true);
78- assert.deepEqual(dom.focused, [search]);
79- dom.active = null;
80- search.remove();
81-});
82-
83-test('prompt without an event does nothing; a dismissal reports its outcome', async () => {
84- assert.equal(await I.prompt(), '');
85- const e = promptEvent('dismissed');
86- fire('beforeinstallprompt', e);
87- assert.equal(await I.prompt(), 'dismissed');
88- assert.equal(button.hidden, true);
89-});
90-
91-test('appinstalled hides the button', () => {
92- fire('beforeinstallprompt', promptEvent());
93- assert.equal(button.hidden, false);
94- fire('appinstalled', {});
95- assert.equal(button.hidden, true);
96-});
97-
98-test('an app that runs installed never shows the button', () => {
99- standalone = true;
100- const e = promptEvent();
101- fire('beforeinstallprompt', e);
102- assert.equal(button.hidden, true);
103- assert.equal(e.prevented, false);
104- standalone = false;
37+test('the page leaves the browser its own install offer', () => {
38+ assert.equal(listeners.beforeinstallprompt, undefined, 'no preventDefault on beforeinstallprompt');
10539 });
@@ -1,22 +1,15 @@
1 // Tests of the install block of static/js/ermite.js (ermiteInstall): the1 // Tests of the install block of static/js/ermite.js (ermiteInstall): the
2-// service worker registration and the "install app" button. Run with2+// service worker registration. Run with
3 // node --test 'internal/adapters/web/jstest/*.test.mjs'3 // node --test 'internal/adapters/web/jstest/*.test.mjs'
4 import assert from 'node:assert/strict';4 import assert from 'node:assert/strict';
5 import { readFileSync } from 'node:fs';5 import { readFileSync } from 'node:fs';
6 import { test } from 'node:test';6 import { test } from 'node:test';
7-import { dom, el, installDom } from './dom.mjs';7+import { installDom } from './dom.mjs';
8 8
9 const doc = installDom();9 const doc = installDom();
10-const button = el('button', { attrs: { 'data-install': '' } });
11-button.hidden = true;
12-document.body.append(button);
13-
14 const setNavigator = (v) => Object.defineProperty(globalThis, 'navigator', { value: v, configurable: true, writable: true });10 const setNavigator = (v) => Object.defineProperty(globalThis, 'navigator', { value: v, configurable: true, writable: true });
15 const listeners = {};11 const listeners = {};
16 globalThis.addEventListener = (type, fn) => { listeners[type] = fn; };12 globalThis.addEventListener = (type, fn) => { listeners[type] = fn; };
17-const fire = (type, ev) => listeners[type](ev);
18-let standalone = false;
19-globalThis.matchMedia = () => ({ matches: standalone });
20 doc.readyState = 'loading';13 doc.readyState = 'loading';
21 const registered = [];14 const registered = [];
22 setNavigator({ serviceWorker: { register: async (url, opts) => { registered.push([url, opts]); return {}; } } });15 setNavigator({ serviceWorker: { register: async (url, opts) => { registered.push([url, opts]); return {}; } } });
@@ -25,17 +18,9 @@ setNavigator({ serviceWorker: { register: async (url, opts) => { registered.push
25 const src = readFileSync(new URL('../static/js/ermite.js', import.meta.url), 'utf8');18 const src = readFileSync(new URL('../static/js/ermite.js', import.meta.url), 'utf8');
26 const start = src.indexOf(' window.ermiteInstall = ');19 const start = src.indexOf(' window.ermiteInstall = ');
27 const end = src.indexOf(' })();', start) + ' })();'.length;20 const end = src.indexOf(' })();', start) + ' })();'.length;
28-new Function('$$', src.slice(start, end))((sel) => document.querySelectorAll(sel));21+new Function(src.slice(start, end))();
29 const I = window.ermiteInstall;22 const I = window.ermiteInstall;
30 23
31-// promptEvent is a beforeinstallprompt event.
32-function promptEvent(outcome = 'accepted') {
33- const e = { prevented: false, prompts: 0, preventDefault() { this.prevented = true; } };
34- e.prompt = async () => { e.prompts++; };
35- e.userChoice = Promise.resolve({ outcome });
36- return e;
37-}
38-
39 test('the service worker is registered at the root scope once the page has loaded', async () => {24 test('the service worker is registered at the root scope once the page has loaded', async () => {
40 assert.equal(registered.length, 0, 'not before load');25 assert.equal(registered.length, 0, 'not before load');
41 await listeners.load();26 await listeners.load();
@@ -49,57 +34,6 @@ test('a refused registration is not an error', async () => {
49 assert.equal(await I.register(), null);34 assert.equal(await I.register(), null);
50 });35 });
51 36
52-test('the button shows on beforeinstallprompt, and a click prompts once', async () => {37+test('the page leaves the browser its own install offer', () => {
53- const e = promptEvent();38+ assert.equal(listeners.beforeinstallprompt, undefined, 'no preventDefault on beforeinstallprompt');
54- assert.equal(button.hidden, true);
55- fire('beforeinstallprompt', e);
56- assert.equal(e.prevented, true, 'the browser banner is replaced by the button');
57- assert.equal(button.hidden, false);
58- const done = listeners.click({ target: { closest: (s) => (s === '[data-install]' ? button : null) } });
59- assert.equal(done, undefined);
60- assert.equal(await I.pending, 'accepted');
61- assert.equal(await I.prompt(), '', 'the event was used by the click');
62- assert.equal(e.prompts, 1);
63- assert.equal(button.hidden, true);
64-});
65-
66-test('the button stays while the dialog is up; its focus then moves to the search', async () => {
67- const search = el('button', { attrs: { 'aria-controls': 'panel-cmd' } });
68- document.body.append(search);
69- const e = promptEvent('dismissed');
70- let shownDuring = null;
71- e.prompt = async () => { shownDuring = !button.hidden; };
72- fire('beforeinstallprompt', e);
73- button.focus();
74- dom.focused = [];
75- assert.equal(await I.prompt(), 'dismissed');
76- assert.equal(shownDuring, true, 'not hidden under the dialog');
77- assert.equal(button.hidden, true);
78- assert.deepEqual(dom.focused, [search]);
79- dom.active = null;
80- search.remove();
81-});
82-
83-test('prompt without an event does nothing; a dismissal reports its outcome', async () => {
84- assert.equal(await I.prompt(), '');
85- const e = promptEvent('dismissed');
86- fire('beforeinstallprompt', e);
87- assert.equal(await I.prompt(), 'dismissed');
88- assert.equal(button.hidden, true);
89-});
90-
91-test('appinstalled hides the button', () => {
92- fire('beforeinstallprompt', promptEvent());
93- assert.equal(button.hidden, false);
94- fire('appinstalled', {});
95- assert.equal(button.hidden, true);
96-});
97-
98-test('an app that runs installed never shows the button', () => {
99- standalone = true;
100- const e = promptEvent();
101- fire('beforeinstallprompt', e);
102- assert.equal(button.hidden, true);
103- assert.equal(e.prevented, false);
104- standalone = false;
105 });39 });
M internal/adapters/web/manifest_test.go +0 -1
@@ -57,7 +57,6 @@ func TestWebAppManifest(t *testing.T) {
5757 page := renderToString(t, Shell(Layout{Assets: u}, nil))
5858 assert.Contains(t, page, `<link rel="manifest" href="`+u.Manifest+`">`)
5959 assert.Contains(t, page, `<link rel="apple-touch-icon" href="`+u.AppleIcon+`">`)
60- assert.Contains(t, page, `data-install`)
6160 }
6261
6362 // The icons are exactly the size the manifest declares: Chrome does not
@@ -57,7 +57,6 @@ func TestWebAppManifest(t *testing.T) {
57 page := renderToString(t, Shell(Layout{Assets: u}, nil))57 page := renderToString(t, Shell(Layout{Assets: u}, nil))
58 assert.Contains(t, page, `<link rel="manifest" href="`+u.Manifest+`">`)58 assert.Contains(t, page, `<link rel="manifest" href="`+u.Manifest+`">`)
59 assert.Contains(t, page, `<link rel="apple-touch-icon" href="`+u.AppleIcon+`">`)59 assert.Contains(t, page, `<link rel="apple-touch-icon" href="`+u.AppleIcon+`">`)
60- assert.Contains(t, page, `data-install`)
61 }60 }
62 61
63 // The icons are exactly the size the manifest declares: Chrome does not62 // The icons are exactly the size the manifest declares: Chrome does not
M internal/adapters/web/mr.go +14 -2
@@ -5,6 +5,7 @@ package web
55 import (
66 "context"
77 "html"
8+ "html/template"
89 "io"
910 "net/http"
1011 "net/url"
@@ -196,7 +197,9 @@ type MRPage struct {
196197 Opened Person
197198 Updated string
198199 UpdatedAt string
199- Desc []TextPart
200+ // Desc is the description rendered as Markdown (as a README: no raw
201+ // HTML, filtered URLs), "" when it is empty.
202+ Desc template.HTML
200203 Head string
201204 HeadShort string
202205 MergedShort string
@@ -469,7 +472,6 @@ func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ
469472 State: mrStateName(m), Open: open, Signed: signed,
470473 Source: visibleText(m.Source), Target: visibleText(m.Target),
471474 Author: s.who(m.Author),
472- Desc: plainParts(m.Description.String()),
473475 Head: head, HeadShort: short(head),
474476 NFiles: res.Stats.FilesChanged,
475477 Adds: res.Stats.Additions,
@@ -477,6 +479,16 @@ func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ
477479 Files: diffFiles(res.Diff.Files),
478480 }
479481 contextGaps(p.Files, res.Diff.Files, repoHref(d.name(), "context", head))
482+ if desc := m.Description.String(); strings.TrimSpace(desc) != "" {
483+ // Relative links point into the source branch as it is now (its head
484+ // commit); the heading ids carry their own prefix, apart from the
485+ // ids of the diff.
486+ h, _, err := s.md.renderWithIDs([]byte(desc), d.name(), head, "", "mr-desc-")
487+ if err != nil {
488+ return nil, 0, err
489+ }
490+ p.Desc = h
491+ }
480492 p.Opened.Name = p.Author
481493 p.Opened.When, p.Opened.WhenAt = whenOf(now, m.CreatedAt)
482494 if !m.CreatedAt.IsZero() {
@@ -5,6 +5,7 @@ package web
5 import (5 import (
6 "context"6 "context"
7 "html"7 "html"
8+ "html/template"
8 "io"9 "io"
9 "net/http"10 "net/http"
10 "net/url"11 "net/url"
@@ -196,7 +197,9 @@ type MRPage struct {
196 Opened Person197 Opened Person
197 Updated string198 Updated string
198 UpdatedAt string199 UpdatedAt string
199- Desc []TextPart200+ // Desc is the description rendered as Markdown (as a README: no raw
201+ // HTML, filtered URLs), "" when it is empty.
202+ Desc template.HTML
200 Head string203 Head string
201 HeadShort string204 HeadShort string
202 MergedShort string205 MergedShort string
@@ -469,7 +472,6 @@ func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ
469 State: mrStateName(m), Open: open, Signed: signed,472 State: mrStateName(m), Open: open, Signed: signed,
470 Source: visibleText(m.Source), Target: visibleText(m.Target),473 Source: visibleText(m.Source), Target: visibleText(m.Target),
471 Author: s.who(m.Author),474 Author: s.who(m.Author),
472- Desc: plainParts(m.Description.String()),
473 Head: head, HeadShort: short(head),475 Head: head, HeadShort: short(head),
474 NFiles: res.Stats.FilesChanged,476 NFiles: res.Stats.FilesChanged,
475 Adds: res.Stats.Additions,477 Adds: res.Stats.Additions,
@@ -477,6 +479,16 @@ func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ
477 Files: diffFiles(res.Diff.Files),479 Files: diffFiles(res.Diff.Files),
478 }480 }
479 contextGaps(p.Files, res.Diff.Files, repoHref(d.name(), "context", head))481 contextGaps(p.Files, res.Diff.Files, repoHref(d.name(), "context", head))
482+ if desc := m.Description.String(); strings.TrimSpace(desc) != "" {
483+ // Relative links point into the source branch as it is now (its head
484+ // commit); the heading ids carry their own prefix, apart from the
485+ // ids of the diff.
486+ h, _, err := s.md.renderWithIDs([]byte(desc), d.name(), head, "", "mr-desc-")
487+ if err != nil {
488+ return nil, 0, err
489+ }
490+ p.Desc = h
491+ }
480 p.Opened.Name = p.Author492 p.Opened.Name = p.Author
481 p.Opened.When, p.Opened.WhenAt = whenOf(now, m.CreatedAt)493 p.Opened.When, p.Opened.WhenAt = whenOf(now, m.CreatedAt)
482 if !m.CreatedAt.IsZero() {494 if !m.CreatedAt.IsZero() {
M internal/adapters/web/mr.templ +5 -3
@@ -140,8 +140,10 @@ templ MergeRequest(l Layout, p MRPage) {
140140 </dl>
141141 </header>
142142 @LiveSlot("mr-notice")
143- if len(p.Desc) > 0 {
144- <p class="mr-desc">@userText(p.Desc)</p>
143+ if p.Desc != "" {
144+ <article class="mr-desc prose" aria-label="description" hx-ignore>
145+ @templ.Raw(string(p.Desc))
146+ </article>
145147 }
146148 if p.Since != nil {
147149 <nav class="since" aria-label="Diff range">
@@ -481,7 +483,7 @@ templ Compare(l Layout, p ComparePage) {
481483 <label for="mr-title">title</label>
482484 <input id="mr-title" name="title" type="text" maxlength="120" required value={ p.Create.Title } autocomplete="off"/>
483485 <label for="mr-desc">description</label>
484- <textarea id="mr-desc" name="description" rows="4" maxlength="8000" placeholder="plain text, optional"></textarea>
486+ <textarea id="mr-desc" name="description" rows="4" maxlength="8000" placeholder="Markdown, optional"></textarea>
485487 <div class="f-btns">
486488 <button type="submit" class="btn primary">Create merge request</button>
487489 </div>
@@ -140,8 +140,10 @@ templ MergeRequest(l Layout, p MRPage) {
140 </dl>140 </dl>
141 </header>141 </header>
142 @LiveSlot("mr-notice")142 @LiveSlot("mr-notice")
143- if len(p.Desc) > 0 {143+ if p.Desc != "" {
144- <p class="mr-desc">@userText(p.Desc)</p>144+ <article class="mr-desc prose" aria-label="description" hx-ignore>
145+ @templ.Raw(string(p.Desc))
146+ </article>
145 }147 }
146 if p.Since != nil {148 if p.Since != nil {
147 <nav class="since" aria-label="Diff range">149 <nav class="since" aria-label="Diff range">
@@ -481,7 +483,7 @@ templ Compare(l Layout, p ComparePage) {
481 <label for="mr-title">title</label>483 <label for="mr-title">title</label>
482 <input id="mr-title" name="title" type="text" maxlength="120" required value={ p.Create.Title } autocomplete="off"/>484 <input id="mr-title" name="title" type="text" maxlength="120" required value={ p.Create.Title } autocomplete="off"/>
483 <label for="mr-desc">description</label>485 <label for="mr-desc">description</label>
484- <textarea id="mr-desc" name="description" rows="4" maxlength="8000" placeholder="plain text, optional"></textarea>486+ <textarea id="mr-desc" name="description" rows="4" maxlength="8000" placeholder="Markdown, optional"></textarea>
485 <div class="f-btns">487 <div class="f-btns">
486 <button type="submit" class="btn primary">Create merge request</button>488 <button type="submit" class="btn primary">Create merge request</button>
487 </div>489 </div>
M internal/adapters/web/mr_templ.go +100 -100
@@ -799,16 +799,16 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
799799 if templ_7745c5c3_Err != nil {
800800 return templ_7745c5c3_Err
801801 }
802- if len(p.Desc) > 0 {
803- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<p class=\"mr-desc\">")
802+ if p.Desc != "" {
803+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<article class=\"mr-desc prose\" aria-label=\"description\" hx-ignore>")
804804 if templ_7745c5c3_Err != nil {
805805 return templ_7745c5c3_Err
806806 }
807- templ_7745c5c3_Err = userText(p.Desc).Render(ctx, templ_7745c5c3_Buffer)
807+ templ_7745c5c3_Err = templ.Raw(string(p.Desc)).Render(ctx, templ_7745c5c3_Buffer)
808808 if templ_7745c5c3_Err != nil {
809809 return templ_7745c5c3_Err
810810 }
811- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</p>")
811+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</article>")
812812 if templ_7745c5c3_Err != nil {
813813 return templ_7745c5c3_Err
814814 }
@@ -825,7 +825,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
825825 var templ_7745c5c3_Var42 templ.SafeURL
826826 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
827827 if templ_7745c5c3_Err != nil {
828- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 149, Col: 42}
828+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 151, Col: 42}
829829 }
830830 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
831831 if templ_7745c5c3_Err != nil {
@@ -848,7 +848,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
848848 var templ_7745c5c3_Var43 string
849849 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
850850 if templ_7745c5c3_Err != nil {
851- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 153, Col: 49}
851+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 49}
852852 }
853853 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
854854 if templ_7745c5c3_Err != nil {
@@ -861,7 +861,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
861861 var templ_7745c5c3_Var44 templ.SafeURL
862862 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
863863 if templ_7745c5c3_Err != nil {
864- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 44}
864+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 157, Col: 44}
865865 }
866866 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
867867 if templ_7745c5c3_Err != nil {
@@ -884,7 +884,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
884884 var templ_7745c5c3_Var45 string
885885 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
886886 if templ_7745c5c3_Err != nil {
887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 159, Col: 64}
887+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 64}
888888 }
889889 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
890890 if templ_7745c5c3_Err != nil {
@@ -897,7 +897,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897897 var templ_7745c5c3_Var46 string
898898 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
899899 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 159, Col: 90}
900+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 90}
901901 }
902902 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
903903 if templ_7745c5c3_Err != nil {
@@ -920,7 +920,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
920920 var templ_7745c5c3_Var47 string
921921 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
922922 if templ_7745c5c3_Err != nil {
923- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 163, Col: 34}
923+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 34}
924924 }
925925 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
926926 if templ_7745c5c3_Err != nil {
@@ -961,7 +961,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
961961 var templ_7745c5c3_Var48 string
962962 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
963963 if templ_7745c5c3_Err != nil {
964- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 29}
964+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 29}
965965 }
966966 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
967967 if templ_7745c5c3_Err != nil {
@@ -984,7 +984,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
984984 var templ_7745c5c3_Var49 string
985985 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
986986 if templ_7745c5c3_Err != nil {
987- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 179, Col: 22}
987+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 181, Col: 22}
988988 }
989989 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)
990990 if templ_7745c5c3_Err != nil {
@@ -1002,7 +1002,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10021002 var templ_7745c5c3_Var50 string
10031003 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
10041004 if templ_7745c5c3_Err != nil {
1005- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 181, Col: 22}
1005+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 183, Col: 22}
10061006 }
10071007 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)
10081008 if templ_7745c5c3_Err != nil {
@@ -1042,7 +1042,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10421042 var templ_7745c5c3_Var51 string
10431043 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
10441044 if templ_7745c5c3_Err != nil {
1045- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 97}
1045+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 97}
10461046 }
10471047 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
10481048 if templ_7745c5c3_Err != nil {
@@ -1055,7 +1055,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
10551055 var templ_7745c5c3_Var52 string
10561056 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
10571057 if templ_7745c5c3_Err != nil {
1058- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 126}
1058+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 126}
10591059 }
10601060 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))
10611061 if templ_7745c5c3_Err != nil {
@@ -1136,7 +1136,7 @@ func branchLink(name, href string) templ.Component {
11361136 var templ_7745c5c3_Var54 templ.SafeURL
11371137 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
11381138 if templ_7745c5c3_Err != nil {
1139- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 212, Col: 31}
1139+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 31}
11401140 }
11411141 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
11421142 if templ_7745c5c3_Err != nil {
@@ -1149,7 +1149,7 @@ func branchLink(name, href string) templ.Component {
11491149 var templ_7745c5c3_Var55 string
11501150 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(name)
11511151 if templ_7745c5c3_Err != nil {
1152- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 212, Col: 40}
1152+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 40}
11531153 }
11541154 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
11551155 if templ_7745c5c3_Err != nil {
@@ -1163,7 +1163,7 @@ func branchLink(name, href string) templ.Component {
11631163 var templ_7745c5c3_Var56 string
11641164 templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(name)
11651165 if templ_7745c5c3_Err != nil {
1166- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 8}
1166+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 216, Col: 8}
11671167 }
11681168 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56))
11691169 if templ_7745c5c3_Err != nil {
@@ -1245,7 +1245,7 @@ func commentView(c CommentView, suffix string) templ.Component {
12451245 var templ_7745c5c3_Var59 string
12461246 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
12471247 if templ_7745c5c3_Err != nil {
1248- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 234, Col: 42}
1248+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 42}
12491249 }
12501250 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var59)
12511251 if templ_7745c5c3_Err != nil {
@@ -1258,7 +1258,7 @@ func commentView(c CommentView, suffix string) templ.Component {
12581258 var templ_7745c5c3_Var60 string
12591259 templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
12601260 if templ_7745c5c3_Err != nil {
1261- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 234, Col: 81}
1261+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 81}
12621262 }
12631263 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var60)
12641264 if templ_7745c5c3_Err != nil {
@@ -1271,7 +1271,7 @@ func commentView(c CommentView, suffix string) templ.Component {
12711271 var templ_7745c5c3_Var61 string
12721272 templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
12731273 if templ_7745c5c3_Err != nil {
1274- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 33}
1274+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 33}
12751275 }
12761276 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))
12771277 if templ_7745c5c3_Err != nil {
@@ -1285,7 +1285,7 @@ func commentView(c CommentView, suffix string) templ.Component {
12851285 var templ_7745c5c3_Var62 string
12861286 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
12871287 if templ_7745c5c3_Err != nil {
1288- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 9}
1288+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 9}
12891289 }
12901290 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
12911291 if templ_7745c5c3_Err != nil {
@@ -1298,7 +1298,7 @@ func commentView(c CommentView, suffix string) templ.Component {
12981298 var templ_7745c5c3_Var63 string
12991299 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
13001300 if templ_7745c5c3_Err != nil {
1301- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 49}
1301+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 49}
13021302 }
13031303 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
13041304 if templ_7745c5c3_Err != nil {
@@ -1311,7 +1311,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13111311 var templ_7745c5c3_Var64 string
13121312 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
13131313 if templ_7745c5c3_Err != nil {
1314- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 65}
1314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 65}
13151315 }
13161316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64)
13171317 if templ_7745c5c3_Err != nil {
@@ -1324,7 +1324,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13241324 var templ_7745c5c3_Var65 string
13251325 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
13261326 if templ_7745c5c3_Err != nil {
1327- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 76}
1327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 76}
13281328 }
13291329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
13301330 if templ_7745c5c3_Err != nil {
@@ -1339,7 +1339,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13391339 var templ_7745c5c3_Var66 string
13401340 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
13411341 if templ_7745c5c3_Err != nil {
1342- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 241, Col: 9}
1342+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 243, Col: 9}
13431343 }
13441344 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))
13451345 if templ_7745c5c3_Err != nil {
@@ -1354,7 +1354,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13541354 var templ_7745c5c3_Var67 string
13551355 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
13561356 if templ_7745c5c3_Err != nil {
1357- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 244, Col: 9}
1357+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 246, Col: 9}
13581358 }
13591359 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))
13601360 if templ_7745c5c3_Err != nil {
@@ -1369,7 +1369,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13691369 var templ_7745c5c3_Var68 string
13701370 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
13711371 if templ_7745c5c3_Err != nil {
1372- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 247, Col: 9}
1372+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 9}
13731373 }
13741374 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
13751375 if templ_7745c5c3_Err != nil {
@@ -1382,7 +1382,7 @@ func commentView(c CommentView, suffix string) templ.Component {
13821382 var templ_7745c5c3_Var69 string
13831383 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
13841384 if templ_7745c5c3_Err != nil {
1385- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 247, Col: 47}
1385+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 47}
13861386 }
13871387 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
13881388 if templ_7745c5c3_Err != nil {
@@ -1413,7 +1413,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14131413 var templ_7745c5c3_Var70 templ.SafeURL
14141414 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
14151415 if templ_7745c5c3_Err != nil {
1416- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 77}
1416+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 77}
14171417 }
14181418 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
14191419 if templ_7745c5c3_Err != nil {
@@ -1426,7 +1426,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14261426 var templ_7745c5c3_Var71 string
14271427 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
14281428 if templ_7745c5c3_Err != nil {
1429- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 74}
1429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 74}
14301430 }
14311431 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)
14321432 if templ_7745c5c3_Err != nil {
@@ -1444,7 +1444,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14441444 var templ_7745c5c3_Var72 string
14451445 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
14461446 if templ_7745c5c3_Err != nil {
1447- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 66}
1447+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 66}
14481448 }
14491449 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72)
14501450 if templ_7745c5c3_Err != nil {
@@ -1462,7 +1462,7 @@ func commentView(c CommentView, suffix string) templ.Component {
14621462 var templ_7745c5c3_Var73 string
14631463 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
14641464 if templ_7745c5c3_Err != nil {
1465- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 55}
1465+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 259, Col: 55}
14661466 }
14671467 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
14681468 if templ_7745c5c3_Err != nil {
@@ -1517,7 +1517,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15171517 var templ_7745c5c3_Var75 templ.SafeURL
15181518 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
15191519 if templ_7745c5c3_Err != nil {
1520- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 272, Col: 67}
1520+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 274, Col: 67}
15211521 }
15221522 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75))
15231523 if templ_7745c5c3_Err != nil {
@@ -1530,7 +1530,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15301530 var templ_7745c5c3_Var76 string
15311531 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
15321532 if templ_7745c5c3_Err != nil {
1533- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 273, Col: 28}
1533+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 28}
15341534 }
15351535 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var76)
15361536 if templ_7745c5c3_Err != nil {
@@ -1543,7 +1543,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15431543 var templ_7745c5c3_Var77 string
15441544 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
15451545 if templ_7745c5c3_Err != nil {
1546- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 273, Col: 40}
1546+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 40}
15471547 }
15481548 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77))
15491549 if templ_7745c5c3_Err != nil {
@@ -1556,7 +1556,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15561556 var templ_7745c5c3_Var78 string
15571557 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
15581558 if templ_7745c5c3_Err != nil {
1559- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 21}
1559+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 277, Col: 21}
15601560 }
15611561 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var78)
15621562 if templ_7745c5c3_Err != nil {
@@ -1584,7 +1584,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15841584 var templ_7745c5c3_Var79 string
15851585 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
15861586 if templ_7745c5c3_Err != nil {
1587- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 286, Col: 50}
1587+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 50}
15881588 }
15891589 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var79)
15901590 if templ_7745c5c3_Err != nil {
@@ -1597,7 +1597,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
15971597 var templ_7745c5c3_Var80 string
15981598 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
15991599 if templ_7745c5c3_Err != nil {
1600- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 287, Col: 50}
1600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 289, Col: 50}
16011601 }
16021602 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
16031603 if templ_7745c5c3_Err != nil {
@@ -1610,7 +1610,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
16101610 var templ_7745c5c3_Var81 string
16111611 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
16121612 if templ_7745c5c3_Err != nil {
1613- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 50}
1613+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 290, Col: 50}
16141614 }
16151615 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var81)
16161616 if templ_7745c5c3_Err != nil {
@@ -1629,7 +1629,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
16291629 var templ_7745c5c3_Var82 string
16301630 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
16311631 if templ_7745c5c3_Err != nil {
1632- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 56}
1632+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 293, Col: 56}
16331633 }
16341634 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
16351635 if templ_7745c5c3_Err != nil {
@@ -1652,7 +1652,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
16521652 var templ_7745c5c3_Var83 templ.SafeURL
16531653 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
16541654 if templ_7745c5c3_Err != nil {
1655- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 49}
1655+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 49}
16561656 }
16571657 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var83))
16581658 if templ_7745c5c3_Err != nil {
@@ -1699,7 +1699,7 @@ func mrRail(p MRPage) templ.Component {
16991699 var templ_7745c5c3_Var85 string
17001700 templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
17011701 if templ_7745c5c3_Err != nil {
1702- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 305, Col: 49}
1702+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 307, Col: 49}
17031703 }
17041704 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85))
17051705 if templ_7745c5c3_Err != nil {
@@ -1728,7 +1728,7 @@ func mrRail(p MRPage) templ.Component {
17281728 var templ_7745c5c3_Var86 string
17291729 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))
17301730 if templ_7745c5c3_Err != nil {
1731- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 314, Col: 71}
1731+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 316, Col: 71}
17321732 }
17331733 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
17341734 if templ_7745c5c3_Err != nil {
@@ -1756,7 +1756,7 @@ func mrRail(p MRPage) templ.Component {
17561756 var templ_7745c5c3_Var87 templ.SafeURL
17571757 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
17581758 if templ_7745c5c3_Err != nil {
1759- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 318, Col: 36}
1759+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 320, Col: 36}
17601760 }
17611761 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87))
17621762 if templ_7745c5c3_Err != nil {
@@ -1769,7 +1769,7 @@ func mrRail(p MRPage) templ.Component {
17691769 var templ_7745c5c3_Var88 string
17701770 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
17711771 if templ_7745c5c3_Err != nil {
1772- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 318, Col: 48}
1772+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 320, Col: 48}
17731773 }
17741774 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
17751775 if templ_7745c5c3_Err != nil {
@@ -1782,7 +1782,7 @@ func mrRail(p MRPage) templ.Component {
17821782 var templ_7745c5c3_Var89 string
17831783 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
17841784 if templ_7745c5c3_Err != nil {
1785- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 319, Col: 32}
1785+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 321, Col: 32}
17861786 }
17871787 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
17881788 if templ_7745c5c3_Err != nil {
@@ -1795,7 +1795,7 @@ func mrRail(p MRPage) templ.Component {
17951795 var templ_7745c5c3_Var90 string
17961796 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
17971797 if templ_7745c5c3_Err != nil {
1798- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 321, Col: 16}
1798+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 16}
17991799 }
18001800 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var90))
18011801 if templ_7745c5c3_Err != nil {
@@ -1809,7 +1809,7 @@ func mrRail(p MRPage) templ.Component {
18091809 var templ_7745c5c3_Var91 string
18101810 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
18111811 if templ_7745c5c3_Err != nil {
1812- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 15}
1812+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 15}
18131813 }
18141814 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91))
18151815 if templ_7745c5c3_Err != nil {
@@ -1822,7 +1822,7 @@ func mrRail(p MRPage) templ.Component {
18221822 var templ_7745c5c3_Var92 string
18231823 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
18241824 if templ_7745c5c3_Err != nil {
1825- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 42}
1825+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 42}
18261826 }
18271827 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
18281828 if templ_7745c5c3_Err != nil {
@@ -1835,7 +1835,7 @@ func mrRail(p MRPage) templ.Component {
18351835 var templ_7745c5c3_Var93 string
18361836 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
18371837 if templ_7745c5c3_Err != nil {
1838- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 53}
1838+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 53}
18391839 }
18401840 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93))
18411841 if templ_7745c5c3_Err != nil {
@@ -1850,7 +1850,7 @@ func mrRail(p MRPage) templ.Component {
18501850 var templ_7745c5c3_Var94 string
18511851 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")
18521852 if templ_7745c5c3_Err != nil {
1853- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 326, Col: 18}
1853+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 18}
18541854 }
18551855 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var94))
18561856 if templ_7745c5c3_Err != nil {
@@ -1880,7 +1880,7 @@ func mrRail(p MRPage) templ.Component {
18801880 var templ_7745c5c3_Var95 string
18811881 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
18821882 if templ_7745c5c3_Err != nil {
1883- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 336, Col: 34}
1883+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 338, Col: 34}
18841884 }
18851885 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))
18861886 if templ_7745c5c3_Err != nil {
@@ -1898,7 +1898,7 @@ func mrRail(p MRPage) templ.Component {
18981898 var templ_7745c5c3_Var96 string
18991899 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
19001900 if templ_7745c5c3_Err != nil {
1901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 343, Col: 36}
1901+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 345, Col: 36}
19021902 }
19031903 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
19041904 if templ_7745c5c3_Err != nil {
@@ -1959,7 +1959,7 @@ func mrBar(p MRPage) templ.Component {
19591959 var templ_7745c5c3_Var98 string
19601960 templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
19611961 if templ_7745c5c3_Err != nil {
1962- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 55}
1962+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 55}
19631963 }
19641964 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
19651965 if templ_7745c5c3_Err != nil {
@@ -1972,7 +1972,7 @@ func mrBar(p MRPage) templ.Component {
19721972 var templ_7745c5c3_Var99 string
19731973 templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
19741974 if templ_7745c5c3_Err != nil {
1975- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 95}
1975+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 95}
19761976 }
19771977 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
19781978 if templ_7745c5c3_Err != nil {
@@ -1985,7 +1985,7 @@ func mrBar(p MRPage) templ.Component {
19851985 var templ_7745c5c3_Var100 string
19861986 templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
19871987 if templ_7745c5c3_Err != nil {
1988- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 140}
1988+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 140}
19891989 }
19901990 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
19911991 if templ_7745c5c3_Err != nil {
@@ -2089,7 +2089,7 @@ func mergeMenu(p MRPage) templ.Component {
20892089 var templ_7745c5c3_Var102 string
20902090 templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(p.HeadShort)
20912091 if templ_7745c5c3_Err != nil {
2092- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 19}
2092+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 397, Col: 19}
20932093 }
20942094 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
20952095 if templ_7745c5c3_Err != nil {
@@ -2103,7 +2103,7 @@ func mergeMenu(p MRPage) templ.Component {
21032103 var templ_7745c5c3_Var103 string
21042104 templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
21052105 if templ_7745c5c3_Err != nil {
2106- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 18}
2106+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 18}
21072107 }
21082108 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
21092109 if templ_7745c5c3_Err != nil {
@@ -2121,7 +2121,7 @@ func mergeMenu(p MRPage) templ.Component {
21212121 var templ_7745c5c3_Var104 templ.SafeURL
21222122 templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
21232123 if templ_7745c5c3_Err != nil {
2124- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 403, Col: 80}
2124+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 405, Col: 80}
21252125 }
21262126 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
21272127 if templ_7745c5c3_Err != nil {
@@ -2139,7 +2139,7 @@ func mergeMenu(p MRPage) templ.Component {
21392139 var templ_7745c5c3_Var105 templ.SafeURL
21402140 templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
21412141 if templ_7745c5c3_Err != nil {
2142- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 407, Col: 80}
2142+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 409, Col: 80}
21432143 }
21442144 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
21452145 if templ_7745c5c3_Err != nil {
@@ -2152,7 +2152,7 @@ func mergeMenu(p MRPage) templ.Component {
21522152 var templ_7745c5c3_Var106 string
21532153 templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
21542154 if templ_7745c5c3_Err != nil {
2155- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 59}
2155+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 410, Col: 59}
21562156 }
21572157 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)
21582158 if templ_7745c5c3_Err != nil {
@@ -2170,7 +2170,7 @@ func mergeMenu(p MRPage) templ.Component {
21702170 var templ_7745c5c3_Var107 string
21712171 templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
21722172 if templ_7745c5c3_Err != nil {
2173- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 413, Col: 55}
2173+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 415, Col: 55}
21742174 }
21752175 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var107)
21762176 if templ_7745c5c3_Err != nil {
@@ -2193,7 +2193,7 @@ func mergeMenu(p MRPage) templ.Component {
21932193 var templ_7745c5c3_Var108 string
21942194 templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
21952195 if templ_7745c5c3_Err != nil {
2196- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 414, Col: 17}
2196+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 416, Col: 17}
21972197 }
21982198 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
21992199 if templ_7745c5c3_Err != nil {
@@ -2211,7 +2211,7 @@ func mergeMenu(p MRPage) templ.Component {
22112211 var templ_7745c5c3_Var109 string
22122212 templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
22132213 if templ_7745c5c3_Err != nil {
2214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 416, Col: 46}
2214+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 418, Col: 46}
22152215 }
22162216 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
22172217 if templ_7745c5c3_Err != nil {
@@ -2239,7 +2239,7 @@ func mergeMenu(p MRPage) templ.Component {
22392239 var templ_7745c5c3_Var110 string
22402240 templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
22412241 if templ_7745c5c3_Err != nil {
2242- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 422, Col: 102}
2242+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 424, Col: 102}
22432243 }
22442244 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
22452245 if templ_7745c5c3_Err != nil {
@@ -2257,7 +2257,7 @@ func mergeMenu(p MRPage) templ.Component {
22572257 var templ_7745c5c3_Var111 string
22582258 templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
22592259 if templ_7745c5c3_Err != nil {
2260- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 425, Col: 82}
2260+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 427, Col: 82}
22612261 }
22622262 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
22632263 if templ_7745c5c3_Err != nil {
@@ -2311,7 +2311,7 @@ func moreMenu(p MRPage) templ.Component {
23112311 var templ_7745c5c3_Var113 templ.SafeURL
23122312 templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
23132313 if templ_7745c5c3_Err != nil {
2314- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 440, Col: 64}
2314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 442, Col: 64}
23152315 }
23162316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
23172317 if templ_7745c5c3_Err != nil {
@@ -2324,7 +2324,7 @@ func moreMenu(p MRPage) templ.Component {
23242324 var templ_7745c5c3_Var114 string
23252325 templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
23262326 if templ_7745c5c3_Err != nil {
2327- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 441, Col: 59}
2327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 443, Col: 59}
23282328 }
23292329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var114)
23302330 if templ_7745c5c3_Err != nil {
@@ -2342,7 +2342,7 @@ func moreMenu(p MRPage) templ.Component {
23422342 var templ_7745c5c3_Var115 templ.SafeURL
23432343 templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
23442344 if templ_7745c5c3_Err != nil {
2345- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 64}
2345+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 64}
23462346 }
23472347 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
23482348 if templ_7745c5c3_Err != nil {
@@ -2414,7 +2414,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24142414 var templ_7745c5c3_Var118 string
24152415 templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
24162416 if templ_7745c5c3_Err != nil {
2417- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 461, Col: 17}
2417+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 17}
24182418 }
24192419 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))
24202420 if templ_7745c5c3_Err != nil {
@@ -2427,7 +2427,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24272427 var templ_7745c5c3_Var119 string
24282428 templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
24292429 if templ_7745c5c3_Err != nil {
2430- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 461, Col: 34}
2430+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 34}
24312431 }
24322432 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
24332433 if templ_7745c5c3_Err != nil {
@@ -2440,7 +2440,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24402440 var templ_7745c5c3_Var120 templ.SafeURL
24412441 templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
24422442 if templ_7745c5c3_Err != nil {
2443- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 464, Col: 45}
2443+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 45}
24442444 }
24452445 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
24462446 if templ_7745c5c3_Err != nil {
@@ -2453,7 +2453,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24532453 var templ_7745c5c3_Var121 string
24542454 templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
24552455 if templ_7745c5c3_Err != nil {
2456- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 464, Col: 58}
2456+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 58}
24572457 }
24582458 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
24592459 if templ_7745c5c3_Err != nil {
@@ -2466,7 +2466,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24662466 var templ_7745c5c3_Var122 templ.SafeURL
24672467 templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
24682468 if templ_7745c5c3_Err != nil {
2469- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 45}
2469+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 45}
24702470 }
24712471 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))
24722472 if templ_7745c5c3_Err != nil {
@@ -2479,7 +2479,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24792479 var templ_7745c5c3_Var123 string
24802480 templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
24812481 if templ_7745c5c3_Err != nil {
2482- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 58}
2482+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 58}
24832483 }
24842484 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var123))
24852485 if templ_7745c5c3_Err != nil {
@@ -2492,7 +2492,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
24922492 var templ_7745c5c3_Var124 string
24932493 templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
24942494 if templ_7745c5c3_Err != nil {
2495- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 21}
2495+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 470, Col: 21}
24962496 }
24972497 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var124))
24982498 if templ_7745c5c3_Err != nil {
@@ -2510,7 +2510,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25102510 var templ_7745c5c3_Var125 string
25112511 templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
25122512 if templ_7745c5c3_Err != nil {
2513- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 472, Col: 29}
2513+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 474, Col: 29}
25142514 }
25152515 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
25162516 if templ_7745c5c3_Err != nil {
@@ -2533,7 +2533,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25332533 var templ_7745c5c3_Var126 templ.SafeURL
25342534 templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
25352535 if templ_7745c5c3_Err != nil {
2536- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 475, Col: 114}
2536+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 477, Col: 114}
25372537 }
25382538 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
25392539 if templ_7745c5c3_Err != nil {
@@ -2546,7 +2546,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25462546 var templ_7745c5c3_Var127 string
25472547 templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
25482548 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 475, Col: 135}
2549+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 477, Col: 135}
25502550 }
25512551 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
25522552 if templ_7745c5c3_Err != nil {
@@ -2569,7 +2569,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25692569 var templ_7745c5c3_Var128 templ.SafeURL
25702570 templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
25712571 if templ_7745c5c3_Err != nil {
2572- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 478, Col: 83}
2572+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 480, Col: 83}
25732573 }
25742574 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var128))
25752575 if templ_7745c5c3_Err != nil {
@@ -2582,7 +2582,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25822582 var templ_7745c5c3_Var129 string
25832583 templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
25842584 if templ_7745c5c3_Err != nil {
2585- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 479, Col: 62}
2585+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 481, Col: 62}
25862586 }
25872587 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var129)
25882588 if templ_7745c5c3_Err != nil {
@@ -2595,7 +2595,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
25952595 var templ_7745c5c3_Var130 string
25962596 templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
25972597 if templ_7745c5c3_Err != nil {
2598- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 480, Col: 62}
2598+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 482, Col: 62}
25992599 }
26002600 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)
26012601 if templ_7745c5c3_Err != nil {
@@ -2608,13 +2608,13 @@ func Compare(l Layout, p ComparePage) templ.Component {
26082608 var templ_7745c5c3_Var131 string
26092609 templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
26102610 if templ_7745c5c3_Err != nil {
2611- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 482, Col: 97}
2611+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 484, Col: 97}
26122612 }
26132613 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
26142614 if templ_7745c5c3_Err != nil {
26152615 return templ_7745c5c3_Err
26162616 }
2617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"plain text, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
2617+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
26182618 if templ_7745c5c3_Err != nil {
26192619 return templ_7745c5c3_Err
26202620 }
@@ -2631,7 +2631,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
26312631 var templ_7745c5c3_Var132 string
26322632 templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
26332633 if templ_7745c5c3_Err != nil {
2634- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 57}
2634+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 57}
26352635 }
26362636 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var132))
26372637 if templ_7745c5c3_Err != nil {
@@ -2644,7 +2644,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
26442644 var templ_7745c5c3_Var133 string
26452645 templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
26462646 if templ_7745c5c3_Err != nil {
2647- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 97}
2647+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 97}
26482648 }
26492649 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var133))
26502650 if templ_7745c5c3_Err != nil {
@@ -2657,7 +2657,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
26572657 var templ_7745c5c3_Var134 string
26582658 templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
26592659 if templ_7745c5c3_Err != nil {
2660- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 142}
2660+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 142}
26612661 }
26622662 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var134))
26632663 if templ_7745c5c3_Err != nil {
@@ -2701,7 +2701,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
27012701 var templ_7745c5c3_Var135 string
27022702 templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
27032703 if templ_7745c5c3_Err != nil {
2704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 507, Col: 23}
2704+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 509, Col: 23}
27052705 }
27062706 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
27072707 if templ_7745c5c3_Err != nil {
@@ -2719,7 +2719,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
27192719 var templ_7745c5c3_Var136 string
27202720 templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
27212721 if templ_7745c5c3_Err != nil {
2722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 509, Col: 23}
2722+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 23}
27232723 }
27242724 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
27252725 if templ_7745c5c3_Err != nil {
@@ -2789,7 +2789,7 @@ func compareRail(p ComparePage) templ.Component {
27892789 var templ_7745c5c3_Var138 string
27902790 templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
27912791 if templ_7745c5c3_Err != nil {
2792- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 525, Col: 67}
2792+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 527, Col: 67}
27932793 }
27942794 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
27952795 if templ_7745c5c3_Err != nil {
@@ -2807,7 +2807,7 @@ func compareRail(p ComparePage) templ.Component {
28072807 var templ_7745c5c3_Var139 templ.SafeURL
28082808 templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
28092809 if templ_7745c5c3_Err != nil {
2810- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 37}
2810+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 531, Col: 37}
28112811 }
28122812 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
28132813 if templ_7745c5c3_Err != nil {
@@ -2820,7 +2820,7 @@ func compareRail(p ComparePage) templ.Component {
28202820 var templ_7745c5c3_Var140 string
28212821 templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
28222822 if templ_7745c5c3_Err != nil {
2823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 49}
2823+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 531, Col: 49}
28242824 }
28252825 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
28262826 if templ_7745c5c3_Err != nil {
@@ -2833,7 +2833,7 @@ func compareRail(p ComparePage) templ.Component {
28332833 var templ_7745c5c3_Var141 string
28342834 templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
28352835 if templ_7745c5c3_Err != nil {
2836- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 530, Col: 32}
2836+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 32}
28372837 }
28382838 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
28392839 if templ_7745c5c3_Err != nil {
@@ -2846,7 +2846,7 @@ func compareRail(p ComparePage) templ.Component {
28462846 var templ_7745c5c3_Var142 string
28472847 templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
28482848 if templ_7745c5c3_Err != nil {
2849- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 16}
2849+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 16}
28502850 }
28512851 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))
28522852 if templ_7745c5c3_Err != nil {
@@ -2860,7 +2860,7 @@ func compareRail(p ComparePage) templ.Component {
28602860 var templ_7745c5c3_Var143 string
28612861 templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
28622862 if templ_7745c5c3_Err != nil {
2863- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 15}
2863+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 15}
28642864 }
28652865 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))
28662866 if templ_7745c5c3_Err != nil {
@@ -2873,7 +2873,7 @@ func compareRail(p ComparePage) templ.Component {
28732873 var templ_7745c5c3_Var144 string
28742874 templ_7745c5c3_Var144, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
28752875 if templ_7745c5c3_Err != nil {
2876- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 42}
2876+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 42}
28772877 }
28782878 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var144)
28792879 if templ_7745c5c3_Err != nil {
@@ -2886,7 +2886,7 @@ func compareRail(p ComparePage) templ.Component {
28862886 var templ_7745c5c3_Var145 string
28872887 templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
28882888 if templ_7745c5c3_Err != nil {
2889- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 53}
2889+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 53}
28902890 }
28912891 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
28922892 if templ_7745c5c3_Err != nil {
@@ -2914,7 +2914,7 @@ func compareRail(p ComparePage) templ.Component {
29142914 var templ_7745c5c3_Var146 string
29152915 templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
29162916 if templ_7745c5c3_Err != nil {
2917- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 541, Col: 47}
2917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 47}
29182918 }
29192919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
29202920 if templ_7745c5c3_Err != nil {
@@ -2937,7 +2937,7 @@ func compareRail(p ComparePage) templ.Component {
29372937 var templ_7745c5c3_Var147 string
29382938 templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
29392939 if templ_7745c5c3_Err != nil {
2940- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 546, Col: 66}
2940+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 548, Col: 66}
29412941 }
29422942 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
29432943 if templ_7745c5c3_Err != nil {
@@ -799,16 +799,16 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
799 if templ_7745c5c3_Err != nil {799 if templ_7745c5c3_Err != nil {
800 return templ_7745c5c3_Err800 return templ_7745c5c3_Err
801 }801 }
802- if len(p.Desc) > 0 {802+ if p.Desc != "" {
803- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<p class=\"mr-desc\">")803+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<article class=\"mr-desc prose\" aria-label=\"description\" hx-ignore>")
804 if templ_7745c5c3_Err != nil {804 if templ_7745c5c3_Err != nil {
805 return templ_7745c5c3_Err805 return templ_7745c5c3_Err
806 }806 }
807- templ_7745c5c3_Err = userText(p.Desc).Render(ctx, templ_7745c5c3_Buffer)807+ templ_7745c5c3_Err = templ.Raw(string(p.Desc)).Render(ctx, templ_7745c5c3_Buffer)
808 if templ_7745c5c3_Err != nil {808 if templ_7745c5c3_Err != nil {
809 return templ_7745c5c3_Err809 return templ_7745c5c3_Err
810 }810 }
811- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</p>")811+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</article>")
812 if templ_7745c5c3_Err != nil {812 if templ_7745c5c3_Err != nil {
813 return templ_7745c5c3_Err813 return templ_7745c5c3_Err
814 }814 }
@@ -825,7 +825,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
825 var templ_7745c5c3_Var42 templ.SafeURL825 var templ_7745c5c3_Var42 templ.SafeURL
826 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))826 templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.AllHref))
827 if templ_7745c5c3_Err != nil {827 if templ_7745c5c3_Err != nil {
828- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 149, Col: 42}828+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 151, Col: 42}
829 }829 }
830 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))830 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
831 if templ_7745c5c3_Err != nil {831 if templ_7745c5c3_Err != nil {
@@ -848,7 +848,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
848 var templ_7745c5c3_Var43 string848 var templ_7745c5c3_Var43 string
849 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)849 templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
850 if templ_7745c5c3_Err != nil {850 if templ_7745c5c3_Err != nil {
851- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 153, Col: 49}851+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 49}
852 }852 }
853 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))853 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
854 if templ_7745c5c3_Err != nil {854 if templ_7745c5c3_Err != nil {
@@ -861,7 +861,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
861 var templ_7745c5c3_Var44 templ.SafeURL861 var templ_7745c5c3_Var44 templ.SafeURL
862 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))862 templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Since.SinceHref))
863 if templ_7745c5c3_Err != nil {863 if templ_7745c5c3_Err != nil {
864- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 155, Col: 44}864+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 157, Col: 44}
865 }865 }
866 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))866 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
867 if templ_7745c5c3_Err != nil {867 if templ_7745c5c3_Err != nil {
@@ -884,7 +884,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
884 var templ_7745c5c3_Var45 string884 var templ_7745c5c3_Var45 string
885 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)885 templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.ReadShort)
886 if templ_7745c5c3_Err != nil {886 if templ_7745c5c3_Err != nil {
887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 159, Col: 64}887+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 64}
888 }888 }
889 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))889 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
890 if templ_7745c5c3_Err != nil {890 if templ_7745c5c3_Err != nil {
@@ -897,7 +897,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
897 var templ_7745c5c3_Var46 string897 var templ_7745c5c3_Var46 string
898 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)898 templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(p.Since.HeadShort)
899 if templ_7745c5c3_Err != nil {899 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 159, Col: 90}900+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 161, Col: 90}
901 }901 }
902 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))902 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
903 if templ_7745c5c3_Err != nil {903 if templ_7745c5c3_Err != nil {
@@ -920,7 +920,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
920 var templ_7745c5c3_Var47 string920 var templ_7745c5c3_Var47 string
921 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)921 templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(p.SinceNote)
922 if templ_7745c5c3_Err != nil {922 if templ_7745c5c3_Err != nil {
923- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 163, Col: 34}923+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 165, Col: 34}
924 }924 }
925 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))925 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
926 if templ_7745c5c3_Err != nil {926 if templ_7745c5c3_Err != nil {
@@ -961,7 +961,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
961 var templ_7745c5c3_Var48 string961 var templ_7745c5c3_Var48 string
962 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)962 templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
963 if templ_7745c5c3_Err != nil {963 if templ_7745c5c3_Err != nil {
964- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 173, Col: 29}964+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 175, Col: 29}
965 }965 }
966 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))966 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
967 if templ_7745c5c3_Err != nil {967 if templ_7745c5c3_Err != nil {
@@ -984,7 +984,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
984 var templ_7745c5c3_Var49 string984 var templ_7745c5c3_Var49 string
985 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)985 templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
986 if templ_7745c5c3_Err != nil {986 if templ_7745c5c3_Err != nil {
987- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 179, Col: 22}987+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 181, Col: 22}
988 }988 }
989 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)989 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)
990 if templ_7745c5c3_Err != nil {990 if templ_7745c5c3_Err != nil {
@@ -1002,7 +1002,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1002 var templ_7745c5c3_Var50 string1002 var templ_7745c5c3_Var50 string
1003 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)1003 templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
1004 if templ_7745c5c3_Err != nil {1004 if templ_7745c5c3_Err != nil {
1005- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 181, Col: 22}1005+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 183, Col: 22}
1006 }1006 }
1007 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)1007 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)
1008 if templ_7745c5c3_Err != nil {1008 if templ_7745c5c3_Err != nil {
@@ -1042,7 +1042,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1042 var templ_7745c5c3_Var51 string1042 var templ_7745c5c3_Var51 string
1043 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))1043 templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NUnresolved))
1044 if templ_7745c5c3_Err != nil {1044 if templ_7745c5c3_Err != nil {
1045- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 97}1045+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 97}
1046 }1046 }
1047 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))1047 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
1048 if templ_7745c5c3_Err != nil {1048 if templ_7745c5c3_Err != nil {
@@ -1055,7 +1055,7 @@ func MergeRequest(l Layout, p MRPage) templ.Component {
1055 var templ_7745c5c3_Var52 string1055 var templ_7745c5c3_Var52 string
1056 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))1056 templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.NComments))
1057 if templ_7745c5c3_Err != nil {1057 if templ_7745c5c3_Err != nil {
1058- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 194, Col: 126}1058+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 196, Col: 126}
1059 }1059 }
1060 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))1060 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))
1061 if templ_7745c5c3_Err != nil {1061 if templ_7745c5c3_Err != nil {
@@ -1136,7 +1136,7 @@ func branchLink(name, href string) templ.Component {
1136 var templ_7745c5c3_Var54 templ.SafeURL1136 var templ_7745c5c3_Var54 templ.SafeURL
1137 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))1137 templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
1138 if templ_7745c5c3_Err != nil {1138 if templ_7745c5c3_Err != nil {
1139- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 212, Col: 31}1139+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 31}
1140 }1140 }
1141 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))1141 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
1142 if templ_7745c5c3_Err != nil {1142 if templ_7745c5c3_Err != nil {
@@ -1149,7 +1149,7 @@ func branchLink(name, href string) templ.Component {
1149 var templ_7745c5c3_Var55 string1149 var templ_7745c5c3_Var55 string
1150 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(name)1150 templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1151 if templ_7745c5c3_Err != nil {1151 if templ_7745c5c3_Err != nil {
1152- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 212, Col: 40}1152+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 40}
1153 }1153 }
1154 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))1154 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
1155 if templ_7745c5c3_Err != nil {1155 if templ_7745c5c3_Err != nil {
@@ -1163,7 +1163,7 @@ func branchLink(name, href string) templ.Component {
1163 var templ_7745c5c3_Var56 string1163 var templ_7745c5c3_Var56 string
1164 templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(name)1164 templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(name)
1165 if templ_7745c5c3_Err != nil {1165 if templ_7745c5c3_Err != nil {
1166- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 214, Col: 8}1166+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 216, Col: 8}
1167 }1167 }
1168 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56))1168 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56))
1169 if templ_7745c5c3_Err != nil {1169 if templ_7745c5c3_Err != nil {
@@ -1245,7 +1245,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1245 var templ_7745c5c3_Var59 string1245 var templ_7745c5c3_Var59 string
1246 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)1246 templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.ResolveAttributeValue("c" + c.ID + suffix)
1247 if templ_7745c5c3_Err != nil {1247 if templ_7745c5c3_Err != nil {
1248- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 234, Col: 42}1248+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 42}
1249 }1249 }
1250 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var59)1250 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var59)
1251 if templ_7745c5c3_Err != nil {1251 if templ_7745c5c3_Err != nil {
@@ -1258,7 +1258,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1258 var templ_7745c5c3_Var60 string1258 var templ_7745c5c3_Var60 string
1259 templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))1259 templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolved))
1260 if templ_7745c5c3_Err != nil {1260 if templ_7745c5c3_Err != nil {
1261- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 234, Col: 81}1261+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 81}
1262 }1262 }
1263 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var60)1263 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var60)
1264 if templ_7745c5c3_Err != nil {1264 if templ_7745c5c3_Err != nil {
@@ -1271,7 +1271,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1271 var templ_7745c5c3_Var61 string1271 var templ_7745c5c3_Var61 string
1272 templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)1272 templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
1273 if templ_7745c5c3_Err != nil {1273 if templ_7745c5c3_Err != nil {
1274- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 236, Col: 33}1274+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 33}
1275 }1275 }
1276 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))1276 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))
1277 if templ_7745c5c3_Err != nil {1277 if templ_7745c5c3_Err != nil {
@@ -1285,7 +1285,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1285 var templ_7745c5c3_Var62 string1285 var templ_7745c5c3_Var62 string
1286 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1286 templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1287 if templ_7745c5c3_Err != nil {1287 if templ_7745c5c3_Err != nil {
1288- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 9}1288+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 9}
1289 }1289 }
1290 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))1290 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
1291 if templ_7745c5c3_Err != nil {1291 if templ_7745c5c3_Err != nil {
@@ -1298,7 +1298,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1298 var templ_7745c5c3_Var63 string1298 var templ_7745c5c3_Var63 string
1299 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)1299 templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
1300 if templ_7745c5c3_Err != nil {1300 if templ_7745c5c3_Err != nil {
1301- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 49}1301+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 49}
1302 }1302 }
1303 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)1303 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var63)
1304 if templ_7745c5c3_Err != nil {1304 if templ_7745c5c3_Err != nil {
@@ -1311,7 +1311,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1311 var templ_7745c5c3_Var64 string1311 var templ_7745c5c3_Var64 string
1312 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)1312 templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.Abs)
1313 if templ_7745c5c3_Err != nil {1313 if templ_7745c5c3_Err != nil {
1314- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 65}1314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 65}
1315 }1315 }
1316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64)1316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var64)
1317 if templ_7745c5c3_Err != nil {1317 if templ_7745c5c3_Err != nil {
@@ -1324,7 +1324,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1324 var templ_7745c5c3_Var65 string1324 var templ_7745c5c3_Var65 string
1325 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)1325 templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
1326 if templ_7745c5c3_Err != nil {1326 if templ_7745c5c3_Err != nil {
1327- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 238, Col: 76}1327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 240, Col: 76}
1328 }1328 }
1329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))1329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
1330 if templ_7745c5c3_Err != nil {1330 if templ_7745c5c3_Err != nil {
@@ -1339,7 +1339,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1339 var templ_7745c5c3_Var66 string1339 var templ_7745c5c3_Var66 string
1340 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1340 templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1341 if templ_7745c5c3_Err != nil {1341 if templ_7745c5c3_Err != nil {
1342- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 241, Col: 9}1342+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 243, Col: 9}
1343 }1343 }
1344 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))1344 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))
1345 if templ_7745c5c3_Err != nil {1345 if templ_7745c5c3_Err != nil {
@@ -1354,7 +1354,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1354 var templ_7745c5c3_Var67 string1354 var templ_7745c5c3_Var67 string
1355 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1355 templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1356 if templ_7745c5c3_Err != nil {1356 if templ_7745c5c3_Err != nil {
1357- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 244, Col: 9}1357+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 246, Col: 9}
1358 }1358 }
1359 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))1359 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))
1360 if templ_7745c5c3_Err != nil {1360 if templ_7745c5c3_Err != nil {
@@ -1369,7 +1369,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1369 var templ_7745c5c3_Var68 string1369 var templ_7745c5c3_Var68 string
1370 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1370 templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1371 if templ_7745c5c3_Err != nil {1371 if templ_7745c5c3_Err != nil {
1372- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 247, Col: 9}1372+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 9}
1373 }1373 }
1374 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))1374 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
1375 if templ_7745c5c3_Err != nil {1375 if templ_7745c5c3_Err != nil {
@@ -1382,7 +1382,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1382 var templ_7745c5c3_Var69 string1382 var templ_7745c5c3_Var69 string
1383 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)1383 templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(c.Where)
1384 if templ_7745c5c3_Err != nil {1384 if templ_7745c5c3_Err != nil {
1385- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 247, Col: 47}1385+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 249, Col: 47}
1386 }1386 }
1387 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))1387 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
1388 if templ_7745c5c3_Err != nil {1388 if templ_7745c5c3_Err != nil {
@@ -1413,7 +1413,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1413 var templ_7745c5c3_Var70 templ.SafeURL1413 var templ_7745c5c3_Var70 templ.SafeURL
1414 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))1414 templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Resolve.Action))
1415 if templ_7745c5c3_Err != nil {1415 if templ_7745c5c3_Err != nil {
1416- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 252, Col: 77}1416+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 254, Col: 77}
1417 }1417 }
1418 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))1418 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
1419 if templ_7745c5c3_Err != nil {1419 if templ_7745c5c3_Err != nil {
@@ -1426,7 +1426,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1426 var templ_7745c5c3_Var71 string1426 var templ_7745c5c3_Var71 string
1427 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))1427 templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(boolText(c.Resolve.Value))
1428 if templ_7745c5c3_Err != nil {1428 if templ_7745c5c3_Err != nil {
1429- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 253, Col: 74}1429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 74}
1430 }1430 }
1431 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)1431 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)
1432 if templ_7745c5c3_Err != nil {1432 if templ_7745c5c3_Err != nil {
@@ -1444,7 +1444,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1444 var templ_7745c5c3_Var72 string1444 var templ_7745c5c3_Var72 string
1445 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))1445 templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(c.Resolve.From))
1446 if templ_7745c5c3_Err != nil {1446 if templ_7745c5c3_Err != nil {
1447- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 255, Col: 66}1447+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 66}
1448 }1448 }
1449 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72)1449 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72)
1450 if templ_7745c5c3_Err != nil {1450 if templ_7745c5c3_Err != nil {
@@ -1462,7 +1462,7 @@ func commentView(c CommentView, suffix string) templ.Component {
1462 var templ_7745c5c3_Var73 string1462 var templ_7745c5c3_Var73 string
1463 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)1463 templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(c.Resolve.Label)
1464 if templ_7745c5c3_Err != nil {1464 if templ_7745c5c3_Err != nil {
1465- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 257, Col: 55}1465+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 259, Col: 55}
1466 }1466 }
1467 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))1467 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73))
1468 if templ_7745c5c3_Err != nil {1468 if templ_7745c5c3_Err != nil {
@@ -1517,7 +1517,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1517 var templ_7745c5c3_Var75 templ.SafeURL1517 var templ_7745c5c3_Var75 templ.SafeURL
1518 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))1518 templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Action))
1519 if templ_7745c5c3_Err != nil {1519 if templ_7745c5c3_Err != nil {
1520- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 272, Col: 67}1520+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 274, Col: 67}
1521 }1521 }
1522 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75))1522 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75))
1523 if templ_7745c5c3_Err != nil {1523 if templ_7745c5c3_Err != nil {
@@ -1530,7 +1530,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1530 var templ_7745c5c3_Var76 string1530 var templ_7745c5c3_Var76 string
1531 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1531 templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1532 if templ_7745c5c3_Err != nil {1532 if templ_7745c5c3_Err != nil {
1533- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 273, Col: 28}1533+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 28}
1534 }1534 }
1535 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var76)1535 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var76)
1536 if templ_7745c5c3_Err != nil {1536 if templ_7745c5c3_Err != nil {
@@ -1543,7 +1543,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1543 var templ_7745c5c3_Var77 string1543 var templ_7745c5c3_Var77 string
1544 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)1544 templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(f.Title)
1545 if templ_7745c5c3_Err != nil {1545 if templ_7745c5c3_Err != nil {
1546- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 273, Col: 40}1546+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 40}
1547 }1547 }
1548 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77))1548 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77))
1549 if templ_7745c5c3_Err != nil {1549 if templ_7745c5c3_Err != nil {
@@ -1556,7 +1556,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1556 var templ_7745c5c3_Var78 string1556 var templ_7745c5c3_Var78 string
1557 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)1557 templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID + suffix)
1558 if templ_7745c5c3_Err != nil {1558 if templ_7745c5c3_Err != nil {
1559- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 275, Col: 21}1559+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 277, Col: 21}
1560 }1560 }
1561 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var78)1561 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var78)
1562 if templ_7745c5c3_Err != nil {1562 if templ_7745c5c3_Err != nil {
@@ -1584,7 +1584,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1584 var templ_7745c5c3_Var79 string1584 var templ_7745c5c3_Var79 string
1585 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)1585 templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
1586 if templ_7745c5c3_Err != nil {1586 if templ_7745c5c3_Err != nil {
1587- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 286, Col: 50}1587+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 50}
1588 }1588 }
1589 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var79)1589 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var79)
1590 if templ_7745c5c3_Err != nil {1590 if templ_7745c5c3_Err != nil {
@@ -1597,7 +1597,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1597 var templ_7745c5c3_Var80 string1597 var templ_7745c5c3_Var80 string
1598 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)1598 templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Line)
1599 if templ_7745c5c3_Err != nil {1599 if templ_7745c5c3_Err != nil {
1600- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 287, Col: 50}1600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 289, Col: 50}
1601 }1601 }
1602 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)1602 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
1603 if templ_7745c5c3_Err != nil {1603 if templ_7745c5c3_Err != nil {
@@ -1610,7 +1610,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1610 var templ_7745c5c3_Var81 string1610 var templ_7745c5c3_Var81 string
1611 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)1611 templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Side)
1612 if templ_7745c5c3_Err != nil {1612 if templ_7745c5c3_Err != nil {
1613- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 288, Col: 50}1613+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 290, Col: 50}
1614 }1614 }
1615 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var81)1615 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var81)
1616 if templ_7745c5c3_Err != nil {1616 if templ_7745c5c3_Err != nil {
@@ -1629,7 +1629,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1629 var templ_7745c5c3_Var82 string1629 var templ_7745c5c3_Var82 string
1630 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))1630 templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(f.From))
1631 if templ_7745c5c3_Err != nil {1631 if templ_7745c5c3_Err != nil {
1632- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 291, Col: 56}1632+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 293, Col: 56}
1633 }1633 }
1634 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)1634 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
1635 if templ_7745c5c3_Err != nil {1635 if templ_7745c5c3_Err != nil {
@@ -1652,7 +1652,7 @@ func commentForm(f CommentForm, suffix string) templ.Component {
1652 var templ_7745c5c3_Var83 templ.SafeURL1652 var templ_7745c5c3_Var83 templ.SafeURL
1653 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))1653 templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(f.Cancel))
1654 if templ_7745c5c3_Err != nil {1654 if templ_7745c5c3_Err != nil {
1655- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 296, Col: 49}1655+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 298, Col: 49}
1656 }1656 }
1657 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var83))1657 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var83))
1658 if templ_7745c5c3_Err != nil {1658 if templ_7745c5c3_Err != nil {
@@ -1699,7 +1699,7 @@ func mrRail(p MRPage) templ.Component {
1699 var templ_7745c5c3_Var85 string1699 var templ_7745c5c3_Var85 string
1700 templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))1700 templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
1701 if templ_7745c5c3_Err != nil {1701 if templ_7745c5c3_Err != nil {
1702- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 305, Col: 49}1702+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 307, Col: 49}
1703 }1703 }
1704 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85))1704 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85))
1705 if templ_7745c5c3_Err != nil {1705 if templ_7745c5c3_Err != nil {
@@ -1728,7 +1728,7 @@ func mrRail(p MRPage) templ.Component {
1728 var templ_7745c5c3_Var86 string1728 var templ_7745c5c3_Var86 string
1729 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))1729 templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Commits)))
1730 if templ_7745c5c3_Err != nil {1730 if templ_7745c5c3_Err != nil {
1731- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 314, Col: 71}1731+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 316, Col: 71}
1732 }1732 }
1733 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))1733 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86))
1734 if templ_7745c5c3_Err != nil {1734 if templ_7745c5c3_Err != nil {
@@ -1756,7 +1756,7 @@ func mrRail(p MRPage) templ.Component {
1756 var templ_7745c5c3_Var87 templ.SafeURL1756 var templ_7745c5c3_Var87 templ.SafeURL
1757 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))1757 templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
1758 if templ_7745c5c3_Err != nil {1758 if templ_7745c5c3_Err != nil {
1759- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 318, Col: 36}1759+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 320, Col: 36}
1760 }1760 }
1761 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87))1761 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87))
1762 if templ_7745c5c3_Err != nil {1762 if templ_7745c5c3_Err != nil {
@@ -1769,7 +1769,7 @@ func mrRail(p MRPage) templ.Component {
1769 var templ_7745c5c3_Var88 string1769 var templ_7745c5c3_Var88 string
1770 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)1770 templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
1771 if templ_7745c5c3_Err != nil {1771 if templ_7745c5c3_Err != nil {
1772- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 318, Col: 48}1772+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 320, Col: 48}
1773 }1773 }
1774 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))1774 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
1775 if templ_7745c5c3_Err != nil {1775 if templ_7745c5c3_Err != nil {
@@ -1782,7 +1782,7 @@ func mrRail(p MRPage) templ.Component {
1782 var templ_7745c5c3_Var89 string1782 var templ_7745c5c3_Var89 string
1783 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)1783 templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
1784 if templ_7745c5c3_Err != nil {1784 if templ_7745c5c3_Err != nil {
1785- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 319, Col: 32}1785+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 321, Col: 32}
1786 }1786 }
1787 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))1787 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
1788 if templ_7745c5c3_Err != nil {1788 if templ_7745c5c3_Err != nil {
@@ -1795,7 +1795,7 @@ func mrRail(p MRPage) templ.Component {
1795 var templ_7745c5c3_Var90 string1795 var templ_7745c5c3_Var90 string
1796 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)1796 templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
1797 if templ_7745c5c3_Err != nil {1797 if templ_7745c5c3_Err != nil {
1798- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 321, Col: 16}1798+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 16}
1799 }1799 }
1800 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var90))1800 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var90))
1801 if templ_7745c5c3_Err != nil {1801 if templ_7745c5c3_Err != nil {
@@ -1809,7 +1809,7 @@ func mrRail(p MRPage) templ.Component {
1809 var templ_7745c5c3_Var91 string1809 var templ_7745c5c3_Var91 string
1810 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")1810 templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
1811 if templ_7745c5c3_Err != nil {1811 if templ_7745c5c3_Err != nil {
1812- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 15}1812+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 15}
1813 }1813 }
1814 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91))1814 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91))
1815 if templ_7745c5c3_Err != nil {1815 if templ_7745c5c3_Err != nil {
@@ -1822,7 +1822,7 @@ func mrRail(p MRPage) templ.Component {
1822 var templ_7745c5c3_Var92 string1822 var templ_7745c5c3_Var92 string
1823 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)1823 templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
1824 if templ_7745c5c3_Err != nil {1824 if templ_7745c5c3_Err != nil {
1825- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 42}1825+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 42}
1826 }1826 }
1827 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)1827 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
1828 if templ_7745c5c3_Err != nil {1828 if templ_7745c5c3_Err != nil {
@@ -1835,7 +1835,7 @@ func mrRail(p MRPage) templ.Component {
1835 var templ_7745c5c3_Var93 string1835 var templ_7745c5c3_Var93 string
1836 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)1836 templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
1837 if templ_7745c5c3_Err != nil {1837 if templ_7745c5c3_Err != nil {
1838- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 323, Col: 53}1838+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 325, Col: 53}
1839 }1839 }
1840 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93))1840 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93))
1841 if templ_7745c5c3_Err != nil {1841 if templ_7745c5c3_Err != nil {
@@ -1850,7 +1850,7 @@ func mrRail(p MRPage) templ.Component {
1850 var templ_7745c5c3_Var94 string1850 var templ_7745c5c3_Var94 string
1851 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")1851 templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.JoinStringErrs(" · new")
1852 if templ_7745c5c3_Err != nil {1852 if templ_7745c5c3_Err != nil {
1853- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 326, Col: 18}1853+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 328, Col: 18}
1854 }1854 }
1855 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var94))1855 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var94))
1856 if templ_7745c5c3_Err != nil {1856 if templ_7745c5c3_Err != nil {
@@ -1880,7 +1880,7 @@ func mrRail(p MRPage) templ.Component {
1880 var templ_7745c5c3_Var95 string1880 var templ_7745c5c3_Var95 string
1881 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)1881 templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(p.CommitsNote)
1882 if templ_7745c5c3_Err != nil {1882 if templ_7745c5c3_Err != nil {
1883- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 336, Col: 34}1883+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 338, Col: 34}
1884 }1884 }
1885 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))1885 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))
1886 if templ_7745c5c3_Err != nil {1886 if templ_7745c5c3_Err != nil {
@@ -1898,7 +1898,7 @@ func mrRail(p MRPage) templ.Component {
1898 var templ_7745c5c3_Var96 string1898 var templ_7745c5c3_Var96 string
1899 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))1899 templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.JoinStringErrs(strings.Join(p.Modes, ", "))
1900 if templ_7745c5c3_Err != nil {1900 if templ_7745c5c3_Err != nil {
1901- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 343, Col: 36}1901+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 345, Col: 36}
1902 }1902 }
1903 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))1903 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var96))
1904 if templ_7745c5c3_Err != nil {1904 if templ_7745c5c3_Err != nil {
@@ -1959,7 +1959,7 @@ func mrBar(p MRPage) templ.Component {
1959 var templ_7745c5c3_Var98 string1959 var templ_7745c5c3_Var98 string
1960 templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))1960 templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
1961 if templ_7745c5c3_Err != nil {1961 if templ_7745c5c3_Err != nil {
1962- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 55}1962+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 55}
1963 }1963 }
1964 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))1964 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
1965 if templ_7745c5c3_Err != nil {1965 if templ_7745c5c3_Err != nil {
@@ -1972,7 +1972,7 @@ func mrBar(p MRPage) templ.Component {
1972 var templ_7745c5c3_Var99 string1972 var templ_7745c5c3_Var99 string
1973 templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))1973 templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
1974 if templ_7745c5c3_Err != nil {1974 if templ_7745c5c3_Err != nil {
1975- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 95}1975+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 95}
1976 }1976 }
1977 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))1977 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
1978 if templ_7745c5c3_Err != nil {1978 if templ_7745c5c3_Err != nil {
@@ -1985,7 +1985,7 @@ func mrBar(p MRPage) templ.Component {
1985 var templ_7745c5c3_Var100 string1985 var templ_7745c5c3_Var100 string
1986 templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))1986 templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
1987 if templ_7745c5c3_Err != nil {1987 if templ_7745c5c3_Err != nil {
1988- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 362, Col: 140}1988+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 364, Col: 140}
1989 }1989 }
1990 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))1990 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
1991 if templ_7745c5c3_Err != nil {1991 if templ_7745c5c3_Err != nil {
@@ -2089,7 +2089,7 @@ func mergeMenu(p MRPage) templ.Component {
2089 var templ_7745c5c3_Var102 string2089 var templ_7745c5c3_Var102 string
2090 templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(p.HeadShort)2090 templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(p.HeadShort)
2091 if templ_7745c5c3_Err != nil {2091 if templ_7745c5c3_Err != nil {
2092- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 395, Col: 19}2092+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 397, Col: 19}
2093 }2093 }
2094 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))2094 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
2095 if templ_7745c5c3_Err != nil {2095 if templ_7745c5c3_Err != nil {
@@ -2103,7 +2103,7 @@ func mergeMenu(p MRPage) templ.Component {
2103 var templ_7745c5c3_Var103 string2103 var templ_7745c5c3_Var103 string
2104 templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2104 templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2105 if templ_7745c5c3_Err != nil {2105 if templ_7745c5c3_Err != nil {
2106- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 399, Col: 18}2106+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 401, Col: 18}
2107 }2107 }
2108 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))2108 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2109 if templ_7745c5c3_Err != nil {2109 if templ_7745c5c3_Err != nil {
@@ -2121,7 +2121,7 @@ func mergeMenu(p MRPage) templ.Component {
2121 var templ_7745c5c3_Var104 templ.SafeURL2121 var templ_7745c5c3_Var104 templ.SafeURL
2122 templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))2122 templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadyAction))
2123 if templ_7745c5c3_Err != nil {2123 if templ_7745c5c3_Err != nil {
2124- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 403, Col: 80}2124+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 405, Col: 80}
2125 }2125 }
2126 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))2126 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2127 if templ_7745c5c3_Err != nil {2127 if templ_7745c5c3_Err != nil {
@@ -2139,7 +2139,7 @@ func mergeMenu(p MRPage) templ.Component {
2139 var templ_7745c5c3_Var105 templ.SafeURL2139 var templ_7745c5c3_Var105 templ.SafeURL
2140 templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))2140 templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.MergeAction))
2141 if templ_7745c5c3_Err != nil {2141 if templ_7745c5c3_Err != nil {
2142- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 407, Col: 80}2142+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 409, Col: 80}
2143 }2143 }
2144 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))2144 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2145 if templ_7745c5c3_Err != nil {2145 if templ_7745c5c3_Err != nil {
@@ -2152,7 +2152,7 @@ func mergeMenu(p MRPage) templ.Component {
2152 var templ_7745c5c3_Var106 string2152 var templ_7745c5c3_Var106 string
2153 templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)2153 templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2154 if templ_7745c5c3_Err != nil {2154 if templ_7745c5c3_Err != nil {
2155- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 408, Col: 59}2155+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 410, Col: 59}
2156 }2156 }
2157 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)2157 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var106)
2158 if templ_7745c5c3_Err != nil {2158 if templ_7745c5c3_Err != nil {
@@ -2170,7 +2170,7 @@ func mergeMenu(p MRPage) templ.Component {
2170 var templ_7745c5c3_Var107 string2170 var templ_7745c5c3_Var107 string
2171 templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)2171 templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.ResolveAttributeValue(m.Value)
2172 if templ_7745c5c3_Err != nil {2172 if templ_7745c5c3_Err != nil {
2173- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 413, Col: 55}2173+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 415, Col: 55}
2174 }2174 }
2175 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var107)2175 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var107)
2176 if templ_7745c5c3_Err != nil {2176 if templ_7745c5c3_Err != nil {
@@ -2193,7 +2193,7 @@ func mergeMenu(p MRPage) templ.Component {
2193 var templ_7745c5c3_Var108 string2193 var templ_7745c5c3_Var108 string
2194 templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)2194 templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(m.Label)
2195 if templ_7745c5c3_Err != nil {2195 if templ_7745c5c3_Err != nil {
2196- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 414, Col: 17}2196+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 416, Col: 17}
2197 }2197 }
2198 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))2198 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
2199 if templ_7745c5c3_Err != nil {2199 if templ_7745c5c3_Err != nil {
@@ -2211,7 +2211,7 @@ func mergeMenu(p MRPage) templ.Component {
2211 var templ_7745c5c3_Var109 string2211 var templ_7745c5c3_Var109 string
2212 templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))2212 templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(i + 1))
2213 if templ_7745c5c3_Err != nil {2213 if templ_7745c5c3_Err != nil {
2214- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 416, Col: 46}2214+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 418, Col: 46}
2215 }2215 }
2216 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))2216 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
2217 if templ_7745c5c3_Err != nil {2217 if templ_7745c5c3_Err != nil {
@@ -2239,7 +2239,7 @@ func mergeMenu(p MRPage) templ.Component {
2239 var templ_7745c5c3_Var110 string2239 var templ_7745c5c3_Var110 string
2240 templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)2240 templ_7745c5c3_Var110, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2241 if templ_7745c5c3_Err != nil {2241 if templ_7745c5c3_Err != nil {
2242- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 422, Col: 102}2242+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 424, Col: 102}
2243 }2243 }
2244 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))2244 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var110))
2245 if templ_7745c5c3_Err != nil {2245 if templ_7745c5c3_Err != nil {
@@ -2257,7 +2257,7 @@ func mergeMenu(p MRPage) templ.Component {
2257 var templ_7745c5c3_Var111 string2257 var templ_7745c5c3_Var111 string
2258 templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2258 templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2259 if templ_7745c5c3_Err != nil {2259 if templ_7745c5c3_Err != nil {
2260- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 425, Col: 82}2260+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 427, Col: 82}
2261 }2261 }
2262 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))2262 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
2263 if templ_7745c5c3_Err != nil {2263 if templ_7745c5c3_Err != nil {
@@ -2311,7 +2311,7 @@ func moreMenu(p MRPage) templ.Component {
2311 var templ_7745c5c3_Var113 templ.SafeURL2311 var templ_7745c5c3_Var113 templ.SafeURL
2312 templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))2312 templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.ReadAction))
2313 if templ_7745c5c3_Err != nil {2313 if templ_7745c5c3_Err != nil {
2314- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 440, Col: 64}2314+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 442, Col: 64}
2315 }2315 }
2316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))2316 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
2317 if templ_7745c5c3_Err != nil {2317 if templ_7745c5c3_Err != nil {
@@ -2324,7 +2324,7 @@ func moreMenu(p MRPage) templ.Component {
2324 var templ_7745c5c3_Var114 string2324 var templ_7745c5c3_Var114 string
2325 templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)2325 templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Box.Head)
2326 if templ_7745c5c3_Err != nil {2326 if templ_7745c5c3_Err != nil {
2327- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 441, Col: 59}2327+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 443, Col: 59}
2328 }2328 }
2329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var114)2329 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var114)
2330 if templ_7745c5c3_Err != nil {2330 if templ_7745c5c3_Err != nil {
@@ -2342,7 +2342,7 @@ func moreMenu(p MRPage) templ.Component {
2342 var templ_7745c5c3_Var115 templ.SafeURL2342 var templ_7745c5c3_Var115 templ.SafeURL
2343 templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))2343 templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Box.CloseAction))
2344 if templ_7745c5c3_Err != nil {2344 if templ_7745c5c3_Err != nil {
2345- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 445, Col: 64}2345+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 447, Col: 64}
2346 }2346 }
2347 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))2347 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
2348 if templ_7745c5c3_Err != nil {2348 if templ_7745c5c3_Err != nil {
@@ -2414,7 +2414,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2414 var templ_7745c5c3_Var118 string2414 var templ_7745c5c3_Var118 string
2415 templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)2415 templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2416 if templ_7745c5c3_Err != nil {2416 if templ_7745c5c3_Err != nil {
2417- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 461, Col: 17}2417+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 17}
2418 }2418 }
2419 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))2419 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))
2420 if templ_7745c5c3_Err != nil {2420 if templ_7745c5c3_Err != nil {
@@ -2427,7 +2427,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2427 var templ_7745c5c3_Var119 string2427 var templ_7745c5c3_Var119 string
2428 templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2428 templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2429 if templ_7745c5c3_Err != nil {2429 if templ_7745c5c3_Err != nil {
2430- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 461, Col: 34}2430+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 463, Col: 34}
2431 }2431 }
2432 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))2432 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
2433 if templ_7745c5c3_Err != nil {2433 if templ_7745c5c3_Err != nil {
@@ -2440,7 +2440,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2440 var templ_7745c5c3_Var120 templ.SafeURL2440 var templ_7745c5c3_Var120 templ.SafeURL
2441 templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))2441 templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.SourceHref))
2442 if templ_7745c5c3_Err != nil {2442 if templ_7745c5c3_Err != nil {
2443- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 464, Col: 45}2443+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 45}
2444 }2444 }
2445 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))2445 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
2446 if templ_7745c5c3_Err != nil {2446 if templ_7745c5c3_Err != nil {
@@ -2453,7 +2453,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2453 var templ_7745c5c3_Var121 string2453 var templ_7745c5c3_Var121 string
2454 templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)2454 templ_7745c5c3_Var121, templ_7745c5c3_Err = templ.JoinStringErrs(p.Source)
2455 if templ_7745c5c3_Err != nil {2455 if templ_7745c5c3_Err != nil {
2456- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 464, Col: 58}2456+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 58}
2457 }2457 }
2458 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))2458 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var121))
2459 if templ_7745c5c3_Err != nil {2459 if templ_7745c5c3_Err != nil {
@@ -2466,7 +2466,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2466 var templ_7745c5c3_Var122 templ.SafeURL2466 var templ_7745c5c3_Var122 templ.SafeURL
2467 templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))2467 templ_7745c5c3_Var122, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.TargetHref))
2468 if templ_7745c5c3_Err != nil {2468 if templ_7745c5c3_Err != nil {
2469- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 45}2469+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 45}
2470 }2470 }
2471 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))2471 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var122))
2472 if templ_7745c5c3_Err != nil {2472 if templ_7745c5c3_Err != nil {
@@ -2479,7 +2479,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2479 var templ_7745c5c3_Var123 string2479 var templ_7745c5c3_Var123 string
2480 templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2480 templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2481 if templ_7745c5c3_Err != nil {2481 if templ_7745c5c3_Err != nil {
2482- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 466, Col: 58}2482+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 58}
2483 }2483 }
2484 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var123))2484 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var123))
2485 if templ_7745c5c3_Err != nil {2485 if templ_7745c5c3_Err != nil {
@@ -2492,7 +2492,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2492 var templ_7745c5c3_Var124 string2492 var templ_7745c5c3_Var124 string
2493 templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)2493 templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.JoinStringErrs(p.AheadText)
2494 if templ_7745c5c3_Err != nil {2494 if templ_7745c5c3_Err != nil {
2495- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 468, Col: 21}2495+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 470, Col: 21}
2496 }2496 }
2497 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var124))2497 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var124))
2498 if templ_7745c5c3_Err != nil {2498 if templ_7745c5c3_Err != nil {
@@ -2510,7 +2510,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2510 var templ_7745c5c3_Var125 string2510 var templ_7745c5c3_Var125 string
2511 templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)2511 templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
2512 if templ_7745c5c3_Err != nil {2512 if templ_7745c5c3_Err != nil {
2513- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 472, Col: 29}2513+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 474, Col: 29}
2514 }2514 }
2515 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))2515 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
2516 if templ_7745c5c3_Err != nil {2516 if templ_7745c5c3_Err != nil {
@@ -2533,7 +2533,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2533 var templ_7745c5c3_Var126 templ.SafeURL2533 var templ_7745c5c3_Var126 templ.SafeURL
2534 templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))2534 templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Existing.Href))
2535 if templ_7745c5c3_Err != nil {2535 if templ_7745c5c3_Err != nil {
2536- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 475, Col: 114}2536+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 477, Col: 114}
2537 }2537 }
2538 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))2538 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
2539 if templ_7745c5c3_Err != nil {2539 if templ_7745c5c3_Err != nil {
@@ -2546,7 +2546,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2546 var templ_7745c5c3_Var127 string2546 var templ_7745c5c3_Var127 string
2547 templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)2547 templ_7745c5c3_Var127, templ_7745c5c3_Err = templ.JoinStringErrs(p.Existing.Label)
2548 if templ_7745c5c3_Err != nil {2548 if templ_7745c5c3_Err != nil {
2549- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 475, Col: 135}2549+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 477, Col: 135}
2550 }2550 }
2551 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))2551 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var127))
2552 if templ_7745c5c3_Err != nil {2552 if templ_7745c5c3_Err != nil {
@@ -2569,7 +2569,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2569 var templ_7745c5c3_Var128 templ.SafeURL2569 var templ_7745c5c3_Var128 templ.SafeURL
2570 templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))2570 templ_7745c5c3_Var128, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(p.Create.Action))
2571 if templ_7745c5c3_Err != nil {2571 if templ_7745c5c3_Err != nil {
2572- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 478, Col: 83}2572+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 480, Col: 83}
2573 }2573 }
2574 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var128))2574 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var128))
2575 if templ_7745c5c3_Err != nil {2575 if templ_7745c5c3_Err != nil {
@@ -2582,7 +2582,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2582 var templ_7745c5c3_Var129 string2582 var templ_7745c5c3_Var129 string
2583 templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)2583 templ_7745c5c3_Var129, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Source)
2584 if templ_7745c5c3_Err != nil {2584 if templ_7745c5c3_Err != nil {
2585- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 479, Col: 62}2585+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 481, Col: 62}
2586 }2586 }
2587 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var129)2587 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var129)
2588 if templ_7745c5c3_Err != nil {2588 if templ_7745c5c3_Err != nil {
@@ -2595,7 +2595,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2595 var templ_7745c5c3_Var130 string2595 var templ_7745c5c3_Var130 string
2596 templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)2596 templ_7745c5c3_Var130, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Target)
2597 if templ_7745c5c3_Err != nil {2597 if templ_7745c5c3_Err != nil {
2598- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 480, Col: 62}2598+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 482, Col: 62}
2599 }2599 }
2600 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)2600 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var130)
2601 if templ_7745c5c3_Err != nil {2601 if templ_7745c5c3_Err != nil {
@@ -2608,13 +2608,13 @@ func Compare(l Layout, p ComparePage) templ.Component {
2608 var templ_7745c5c3_Var131 string2608 var templ_7745c5c3_Var131 string
2609 templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)2609 templ_7745c5c3_Var131, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.Create.Title)
2610 if templ_7745c5c3_Err != nil {2610 if templ_7745c5c3_Err != nil {
2611- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 482, Col: 97}2611+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 484, Col: 97}
2612 }2612 }
2613 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)2613 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var131)
2614 if templ_7745c5c3_Err != nil {2614 if templ_7745c5c3_Err != nil {
2615 return templ_7745c5c3_Err2615 return templ_7745c5c3_Err
2616 }2616 }
2617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"plain text, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")2617+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "\" autocomplete=\"off\"> <label for=\"mr-desc\">description</label> <textarea id=\"mr-desc\" name=\"description\" rows=\"4\" maxlength=\"8000\" placeholder=\"Markdown, optional\"></textarea><div class=\"f-btns\"><button type=\"submit\" class=\"btn primary\">Create merge request</button></div></form>")
2618 if templ_7745c5c3_Err != nil {2618 if templ_7745c5c3_Err != nil {
2619 return templ_7745c5c3_Err2619 return templ_7745c5c3_Err
2620 }2620 }
@@ -2631,7 +2631,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2631 var templ_7745c5c3_Var132 string2631 var templ_7745c5c3_Var132 string
2632 templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))2632 templ_7745c5c3_Var132, templ_7745c5c3_Err = templ.JoinStringErrs(plural(p.NFiles, "file", "files"))
2633 if templ_7745c5c3_Err != nil {2633 if templ_7745c5c3_Err != nil {
2634- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 57}2634+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 57}
2635 }2635 }
2636 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var132))2636 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var132))
2637 if templ_7745c5c3_Err != nil {2637 if templ_7745c5c3_Err != nil {
@@ -2644,7 +2644,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2644 var templ_7745c5c3_Var133 string2644 var templ_7745c5c3_Var133 string
2645 templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))2645 templ_7745c5c3_Var133, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Adds))
2646 if templ_7745c5c3_Err != nil {2646 if templ_7745c5c3_Err != nil {
2647- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 97}2647+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 97}
2648 }2648 }
2649 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var133))2649 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var133))
2650 if templ_7745c5c3_Err != nil {2650 if templ_7745c5c3_Err != nil {
@@ -2657,7 +2657,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2657 var templ_7745c5c3_Var134 string2657 var templ_7745c5c3_Var134 string
2658 templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))2658 templ_7745c5c3_Var134, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(p.Dels))
2659 if templ_7745c5c3_Err != nil {2659 if templ_7745c5c3_Err != nil {
2660- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 492, Col: 142}2660+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 494, Col: 142}
2661 }2661 }
2662 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var134))2662 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var134))
2663 if templ_7745c5c3_Err != nil {2663 if templ_7745c5c3_Err != nil {
@@ -2701,7 +2701,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2701 var templ_7745c5c3_Var135 string2701 var templ_7745c5c3_Var135 string
2702 templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)2702 templ_7745c5c3_Var135, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
2703 if templ_7745c5c3_Err != nil {2703 if templ_7745c5c3_Err != nil {
2704- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 507, Col: 23}2704+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 509, Col: 23}
2705 }2705 }
2706 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)2706 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var135)
2707 if templ_7745c5c3_Err != nil {2707 if templ_7745c5c3_Err != nil {
@@ -2719,7 +2719,7 @@ func Compare(l Layout, p ComparePage) templ.Component {
2719 var templ_7745c5c3_Var136 string2719 var templ_7745c5c3_Var136 string
2720 templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)2720 templ_7745c5c3_Var136, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
2721 if templ_7745c5c3_Err != nil {2721 if templ_7745c5c3_Err != nil {
2722- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 509, Col: 23}2722+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 511, Col: 23}
2723 }2723 }
2724 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)2724 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var136)
2725 if templ_7745c5c3_Err != nil {2725 if templ_7745c5c3_Err != nil {
@@ -2789,7 +2789,7 @@ func compareRail(p ComparePage) templ.Component {
2789 var templ_7745c5c3_Var138 string2789 var templ_7745c5c3_Var138 string
2790 templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))2790 templ_7745c5c3_Var138, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Ahead)))
2791 if templ_7745c5c3_Err != nil {2791 if templ_7745c5c3_Err != nil {
2792- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 525, Col: 67}2792+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 527, Col: 67}
2793 }2793 }
2794 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))2794 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var138))
2795 if templ_7745c5c3_Err != nil {2795 if templ_7745c5c3_Err != nil {
@@ -2807,7 +2807,7 @@ func compareRail(p ComparePage) templ.Component {
2807 var templ_7745c5c3_Var139 templ.SafeURL2807 var templ_7745c5c3_Var139 templ.SafeURL
2808 templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))2808 templ_7745c5c3_Var139, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.CHref))
2809 if templ_7745c5c3_Err != nil {2809 if templ_7745c5c3_Err != nil {
2810- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 37}2810+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 531, Col: 37}
2811 }2811 }
2812 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))2812 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var139))
2813 if templ_7745c5c3_Err != nil {2813 if templ_7745c5c3_Err != nil {
@@ -2820,7 +2820,7 @@ func compareRail(p ComparePage) templ.Component {
2820 var templ_7745c5c3_Var140 string2820 var templ_7745c5c3_Var140 string
2821 templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)2821 templ_7745c5c3_Var140, templ_7745c5c3_Err = templ.JoinStringErrs(c.Short)
2822 if templ_7745c5c3_Err != nil {2822 if templ_7745c5c3_Err != nil {
2823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 529, Col: 49}2823+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 531, Col: 49}
2824 }2824 }
2825 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))2825 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var140))
2826 if templ_7745c5c3_Err != nil {2826 if templ_7745c5c3_Err != nil {
@@ -2833,7 +2833,7 @@ func compareRail(p ComparePage) templ.Component {
2833 var templ_7745c5c3_Var141 string2833 var templ_7745c5c3_Var141 string
2834 templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)2834 templ_7745c5c3_Var141, templ_7745c5c3_Err = templ.JoinStringErrs(c.Subject)
2835 if templ_7745c5c3_Err != nil {2835 if templ_7745c5c3_Err != nil {
2836- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 530, Col: 32}2836+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 32}
2837 }2837 }
2838 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))2838 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var141))
2839 if templ_7745c5c3_Err != nil {2839 if templ_7745c5c3_Err != nil {
@@ -2846,7 +2846,7 @@ func compareRail(p ComparePage) templ.Component {
2846 var templ_7745c5c3_Var142 string2846 var templ_7745c5c3_Var142 string
2847 templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)2847 templ_7745c5c3_Var142, templ_7745c5c3_Err = templ.JoinStringErrs(c.Author)
2848 if templ_7745c5c3_Err != nil {2848 if templ_7745c5c3_Err != nil {
2849- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 532, Col: 16}2849+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 16}
2850 }2850 }
2851 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))2851 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var142))
2852 if templ_7745c5c3_Err != nil {2852 if templ_7745c5c3_Err != nil {
@@ -2860,7 +2860,7 @@ func compareRail(p ComparePage) templ.Component {
2860 var templ_7745c5c3_Var143 string2860 var templ_7745c5c3_Var143 string
2861 templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")2861 templ_7745c5c3_Var143, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
2862 if templ_7745c5c3_Err != nil {2862 if templ_7745c5c3_Err != nil {
2863- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 15}2863+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 15}
2864 }2864 }
2865 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))2865 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var143))
2866 if templ_7745c5c3_Err != nil {2866 if templ_7745c5c3_Err != nil {
@@ -2873,7 +2873,7 @@ func compareRail(p ComparePage) templ.Component {
2873 var templ_7745c5c3_Var144 string2873 var templ_7745c5c3_Var144 string
2874 templ_7745c5c3_Var144, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)2874 templ_7745c5c3_Var144, templ_7745c5c3_Err = templ.ResolveAttributeValue(c.WhenAt)
2875 if templ_7745c5c3_Err != nil {2875 if templ_7745c5c3_Err != nil {
2876- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 42}2876+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 42}
2877 }2877 }
2878 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var144)2878 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var144)
2879 if templ_7745c5c3_Err != nil {2879 if templ_7745c5c3_Err != nil {
@@ -2886,7 +2886,7 @@ func compareRail(p ComparePage) templ.Component {
2886 var templ_7745c5c3_Var145 string2886 var templ_7745c5c3_Var145 string
2887 templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)2887 templ_7745c5c3_Var145, templ_7745c5c3_Err = templ.JoinStringErrs(c.When)
2888 if templ_7745c5c3_Err != nil {2888 if templ_7745c5c3_Err != nil {
2889- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 534, Col: 53}2889+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 536, Col: 53}
2890 }2890 }
2891 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))2891 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var145))
2892 if templ_7745c5c3_Err != nil {2892 if templ_7745c5c3_Err != nil {
@@ -2914,7 +2914,7 @@ func compareRail(p ComparePage) templ.Component {
2914 var templ_7745c5c3_Var146 string2914 var templ_7745c5c3_Var146 string
2915 templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)2915 templ_7745c5c3_Var146, templ_7745c5c3_Err = templ.JoinStringErrs(p.Target)
2916 if templ_7745c5c3_Err != nil {2916 if templ_7745c5c3_Err != nil {
2917- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 541, Col: 47}2917+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 543, Col: 47}
2918 }2918 }
2919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))2919 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var146))
2920 if templ_7745c5c3_Err != nil {2920 if templ_7745c5c3_Err != nil {
@@ -2937,7 +2937,7 @@ func compareRail(p ComparePage) templ.Component {
2937 var templ_7745c5c3_Var147 string2937 var templ_7745c5c3_Var147 string
2938 templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))2938 templ_7745c5c3_Var147, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
2939 if templ_7745c5c3_Err != nil {2939 if templ_7745c5c3_Err != nil {
2940- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 546, Col: 66}2940+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/mr.templ`, Line: 548, Col: 66}
2941 }2941 }
2942 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))2942 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var147))
2943 if templ_7745c5c3_Err != nil {2943 if templ_7745c5c3_Err != nil {
M internal/adapters/web/pages.templ +3 -2
@@ -68,10 +68,11 @@ templ latestTagFact(t LatestTag) {
6868 <dt>latest tag</dt>
6969 <dd class="latest-tag">
7070 if t.Name != "" {
71- <a class="tag-name" href={ templ.SafeURL(t.Href) } title={ t.Subject }><span class="ico i-tag" aria-hidden="true"></span>{ t.Name }</a>
71+ <a class="tag-name" href={ templ.SafeURL(t.Href) } title={ t.Subject }>{ t.Name }</a>
7272 if t.WhenAt != "" {
73- <time class="dim" datetime={ t.WhenAt } title={ t.WhenAt }>{ t.When }</time>
73+ { " · " }<time datetime={ t.WhenAt } title={ t.WhenAt }>{ t.When }</time>
7474 }
75+ { " · " }
7576 }
7677 <a class="all-tags" href={ templ.SafeURL(t.RefsHref) }>{ plural(t.Count, "tag", "tags") }</a>
7778 </dd>
@@ -68,10 +68,11 @@ templ latestTagFact(t LatestTag) {
68 <dt>latest tag</dt>68 <dt>latest tag</dt>
69 <dd class="latest-tag">69 <dd class="latest-tag">
70 if t.Name != "" {70 if t.Name != "" {
71- <a class="tag-name" href={ templ.SafeURL(t.Href) } title={ t.Subject }><span class="ico i-tag" aria-hidden="true"></span>{ t.Name }</a>71+ <a class="tag-name" href={ templ.SafeURL(t.Href) } title={ t.Subject }>{ t.Name }</a>
72 if t.WhenAt != "" {72 if t.WhenAt != "" {
73- <time class="dim" datetime={ t.WhenAt } title={ t.WhenAt }>{ t.When }</time>73+ { " · " }<time datetime={ t.WhenAt } title={ t.WhenAt }>{ t.When }</time>
74 }74 }
75+ { " · " }
75 }76 }
76 <a class="all-tags" href={ templ.SafeURL(t.RefsHref) }>{ plural(t.Count, "tag", "tags") }</a>77 <a class="all-tags" href={ templ.SafeURL(t.RefsHref) }>{ plural(t.Count, "tag", "tags") }</a>
77 </dd>78 </dd>
M internal/adapters/web/pages_templ.go +325 -299 generated file: collapsed
M internal/adapters/web/shell.templ +0 -10
@@ -128,16 +128,6 @@ templ Header(l Layout) {
128128 <span class="search-label">Go to…</span>
129129 <kbd aria-hidden="true">ctrl k</kbd>
130130 </button>
131- <button
132- type="button"
133- class="btn icon"
134- data-install
135- hidden
136- aria-label="Install app"
137- title="install ermite as an app"
138- >
139- <span class="ico i-download" aria-hidden="true"></span>
140- </button>
141131 if SignedIn(ctx) {
142132 <form class="owner" method="post" action="/-/logout">
143133 <span class="owner-badge" title="signed in as the owner"><span class="ico i-user" aria-hidden="true"></span>{ l.Owner }</span>
@@ -128,16 +128,6 @@ templ Header(l Layout) {
128 <span class="search-label">Go to…</span>128 <span class="search-label">Go to…</span>
129 <kbd aria-hidden="true">ctrl k</kbd>129 <kbd aria-hidden="true">ctrl k</kbd>
130 </button>130 </button>
131- <button
132- type="button"
133- class="btn icon"
134- data-install
135- hidden
136- aria-label="Install app"
137- title="install ermite as an app"
138- >
139- <span class="ico i-download" aria-hidden="true"></span>
140- </button>
141 if SignedIn(ctx) {131 if SignedIn(ctx) {
142 <form class="owner" method="post" action="/-/logout">132 <form class="owner" method="post" action="/-/logout">
143 <span class="owner-badge" title="signed in as the owner"><span class="ico i-user" aria-hidden="true"></span>{ l.Owner }</span>133 <span class="owner-badge" title="signed in as the owner"><span class="ico i-user" aria-hidden="true"></span>{ l.Owner }</span>
M internal/adapters/web/shell_templ.go +11 -11 generated file: collapsed
M internal/adapters/web/static/css/20-shell.css +5 -9
@@ -26,7 +26,6 @@
2626 .i-key { --i: url(icons/key.svg); }
2727 .i-log-in { --i: url(icons/log-in.svg); }
2828 .i-log-out { --i: url(icons/log-out.svg); }
29- .i-download { --i: url(icons/download.svg); }
3029
3130 .pill {
3231 display: inline-flex; align-items: center; height: 20px; padding: 0 var(--s2); margin-left: var(--s1);
@@ -135,15 +134,12 @@
135134 .rail section > .list { margin: var(--s2) 0; }
136135 .rail section > p + p { margin-top: calc(-1 * var(--s2)); }
137136
138- /* newest tag, a row of About in the summary rail */
137+ /* newest tag, a row of About in the summary rail: one line of text like
138+ the rows above it ("v0.9.0 · 36h ago · 9 tags") */
139139 .kv dd.latest-tag {
140- display: flex; align-items: baseline; gap: var(--s2);
141- & .tag-name { display: inline-flex; align-items: center; gap: 4px; min-width: 0; overflow: hidden; font-weight: 700; font-family: var(--mono); color: var(--ink-hi); text-decoration: none; }
142- & .tag-name .ico { flex: none; }
143- & .tag-name:hover { text-decoration: underline; }
144- & time { white-space: nowrap; }
145- & .all-tags { margin-left: auto; white-space: nowrap; color: var(--ink-dim); text-decoration: none; }
146- & .all-tags:hover { color: var(--ink-hi); text-decoration: underline; }
140+ & a { color: inherit; text-decoration: none; }
141+ & .tag-name { font-weight: 700; color: var(--ink-hi); }
142+ & a:hover { color: var(--ink-hi); text-decoration: underline; }
147143 }
148144
149145 .kv {
@@ -26,7 +26,6 @@
26 .i-key { --i: url(icons/key.svg); }26 .i-key { --i: url(icons/key.svg); }
27 .i-log-in { --i: url(icons/log-in.svg); }27 .i-log-in { --i: url(icons/log-in.svg); }
28 .i-log-out { --i: url(icons/log-out.svg); }28 .i-log-out { --i: url(icons/log-out.svg); }
29- .i-download { --i: url(icons/download.svg); }
30 29
31 .pill {30 .pill {
32 display: inline-flex; align-items: center; height: 20px; padding: 0 var(--s2); margin-left: var(--s1);31 display: inline-flex; align-items: center; height: 20px; padding: 0 var(--s2); margin-left: var(--s1);
@@ -135,15 +134,12 @@
135 .rail section > .list { margin: var(--s2) 0; }134 .rail section > .list { margin: var(--s2) 0; }
136 .rail section > p + p { margin-top: calc(-1 * var(--s2)); }135 .rail section > p + p { margin-top: calc(-1 * var(--s2)); }
137 136
138- /* newest tag, a row of About in the summary rail */137+ /* newest tag, a row of About in the summary rail: one line of text like
138+ the rows above it ("v0.9.0 · 36h ago · 9 tags") */
139 .kv dd.latest-tag {139 .kv dd.latest-tag {
140- display: flex; align-items: baseline; gap: var(--s2);140+ & a { color: inherit; text-decoration: none; }
141- & .tag-name { display: inline-flex; align-items: center; gap: 4px; min-width: 0; overflow: hidden; font-weight: 700; font-family: var(--mono); color: var(--ink-hi); text-decoration: none; }141+ & .tag-name { font-weight: 700; color: var(--ink-hi); }
142- & .tag-name .ico { flex: none; }142+ & a:hover { color: var(--ink-hi); text-decoration: underline; }
143- & .tag-name:hover { text-decoration: underline; }
144- & time { white-space: nowrap; }
145- & .all-tags { margin-left: auto; white-space: nowrap; color: var(--ink-dim); text-decoration: none; }
146- & .all-tags:hover { color: var(--ink-hi); text-decoration: underline; }
147 }143 }
148 144
149 .kv {145 .kv {
M internal/adapters/web/static/css/60-mr.css +6 -2
@@ -6,8 +6,12 @@
66 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }
77 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }
88 .mr-state[data-state="draft"]::before { content: "◌ "; color: var(--ink-dim); }
9- .mr-desc { max-width: var(--measure); white-space: pre-wrap; overflow-wrap: anywhere; padding: var(--s4) var(--s5); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r); }
10- .mr-desc a, .c-text a { text-decoration: underline; }
9+ /* the description: Markdown as a README, as wide as the header card above;
10+ the text inside keeps the reading measure */
11+ .mr-desc.prose { max-width: none; padding: var(--s4) var(--s5); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r); }
12+ .mr-desc.prose > * { max-width: var(--measure); }
13+ .mr-desc.prose > pre, .mr-desc.prose > table { max-width: 100%; }
14+ .c-text a { text-decoration: underline; }
1115
1216 .since {
1317 display: inline-flex; flex-wrap: wrap; gap: var(--s1); padding: var(--s1);
@@ -6,8 +6,12 @@
6 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }6 .mr-state[data-state="merged"]::before { content: "✓ "; color: var(--teal); }
7 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }7 .mr-state[data-state="closed"]::before { content: "✗ "; color: var(--red); }
8 .mr-state[data-state="draft"]::before { content: "◌ "; color: var(--ink-dim); }8 .mr-state[data-state="draft"]::before { content: "◌ "; color: var(--ink-dim); }
9- .mr-desc { max-width: var(--measure); white-space: pre-wrap; overflow-wrap: anywhere; padding: var(--s4) var(--s5); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r); }9+ /* the description: Markdown as a README, as wide as the header card above;
10- .mr-desc a, .c-text a { text-decoration: underline; }10+ the text inside keeps the reading measure */
11+ .mr-desc.prose { max-width: none; padding: var(--s4) var(--s5); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r); }
12+ .mr-desc.prose > * { max-width: var(--measure); }
13+ .mr-desc.prose > pre, .mr-desc.prose > table { max-width: 100%; }
14+ .c-text a { text-decoration: underline; }
11 15
12 .since {16 .since {
13 display: inline-flex; flex-wrap: wrap; gap: var(--s1); padding: var(--s1);17 display: inline-flex; flex-wrap: wrap; gap: var(--s1); padding: var(--s1);
D internal/adapters/web/static/icons/download.svg +0 -1
@@ -1,1 +0,0 @@
1-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/></svg>
@@ -1,1 +0,0 @@
1-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/></svg>
M internal/adapters/web/static/js/ermite.js +6 -51
@@ -11,7 +11,7 @@
1111 // 4. The file of the diff in view is marked in the table of contents.
1212 // 5. A handler that fails is shown in the hint badge.
1313 // 6. The lines a diff hides load in place (ermiteGaps; e and E).
14-// 7. The service worker and the "install app" button (ermiteInstall).
14+// 7. The service worker (ermiteInstall).
1515 (() => {
1616 // Marks the page as scripted: what does nothing without scripts (the filters,
1717 // the "go to" and help buttons) is hidden until this class is set (see the
@@ -366,20 +366,12 @@
366366 };
367367 })();
368368
369- // The installed app. The service worker (/-/sw.js) is registered once the page
370- // has loaded. Chrome offers the install by itself only as an icon in the
371- // address bar of a desktop (or a mini-bar on a phone): the page keeps the
372- // beforeinstallprompt event and shows its own button ([data-install] in the
373- // header), which asks the browser to prompt. The button stays hidden when the
374- // app is already running installed or once it was installed. Self-contained:
375- // jstest/install.test.mjs evaluates this block alone.
369+ // The installed app: the service worker (/-/sw.js) is registered once the
370+ // page has loaded. With it and the manifest the browser offers the install
371+ // by itself (the address bar of a desktop, the menu or a banner on a phone);
372+ // the page leaves that offer alone. Self-contained: jstest/install.test.mjs
373+ // evaluates this block alone.
376374 window.ermiteInstall = (() => {
377- let deferred = null;
378- const buttons = () => $$('[data-install]');
379- const show = (on) => { for (const b of buttons()) b.hidden = !on; };
380- const installed = () =>
381- !!window.matchMedia?.('(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)').matches ||
382- navigator.standalone === true;
383375 const api = {
384376 // register installs the service worker; a browser without one, or a
385377 // refusal, leaves the site working as before.
@@ -387,44 +379,7 @@
387379 if (!navigator.serviceWorker) return Promise.resolve(null);
388380 return navigator.serviceWorker.register('/-/sw.js', { scope: '/' }).catch(() => null);
389381 },
390- // offer keeps the event the browser sent and shows the button.
391- offer(e) {
392- if (installed()) return;
393- e.preventDefault();
394- deferred = e;
395- show(true);
396- },
397- // prompt asks the browser to show its install dialog. The event works
398- // once: a new one comes if the visitor dismisses the dialog. The button
399- // stays while the dialog is up; once it hides, the focus it held moves
400- // to the search of the header rather than to the body.
401- async prompt() {
402- const e = deferred;
403- if (!e) return '';
404- deferred = null;
405- let outcome = '';
406- try {
407- await e.prompt();
408- outcome = (await e.userChoice).outcome;
409- } catch {
410- outcome = '';
411- }
412- const had = buttons().some((b) => b === document.activeElement);
413- show(false);
414- if (had) document.querySelector('[aria-controls="panel-cmd"]')?.focus?.();
415- return outcome;
416- },
417- done() {
418- deferred = null;
419- show(false);
420- },
421382 };
422- addEventListener('beforeinstallprompt', api.offer);
423- addEventListener('appinstalled', api.done);
424- addEventListener('click', (e) => {
425- // pending is the prompt the last click started (its outcome)
426- if (e.target.closest?.('[data-install]')) api.pending = api.prompt();
427- });
428383 if (document.readyState === 'complete') api.register();
429384 else addEventListener('load', () => api.register(), { once: true });
430385 return api;
@@ -11,7 +11,7 @@
11 // 4. The file of the diff in view is marked in the table of contents.11 // 4. The file of the diff in view is marked in the table of contents.
12 // 5. A handler that fails is shown in the hint badge.12 // 5. A handler that fails is shown in the hint badge.
13 // 6. The lines a diff hides load in place (ermiteGaps; e and E).13 // 6. The lines a diff hides load in place (ermiteGaps; e and E).
14-// 7. The service worker and the "install app" button (ermiteInstall).14+// 7. The service worker (ermiteInstall).
15 (() => {15 (() => {
16 // Marks the page as scripted: what does nothing without scripts (the filters,16 // Marks the page as scripted: what does nothing without scripts (the filters,
17 // the "go to" and help buttons) is hidden until this class is set (see the17 // the "go to" and help buttons) is hidden until this class is set (see the
@@ -366,20 +366,12 @@
366 };366 };
367 })();367 })();
368 368
369- // The installed app. The service worker (/-/sw.js) is registered once the page369+ // The installed app: the service worker (/-/sw.js) is registered once the
370- // has loaded. Chrome offers the install by itself only as an icon in the370+ // page has loaded. With it and the manifest the browser offers the install
371- // address bar of a desktop (or a mini-bar on a phone): the page keeps the371+ // by itself (the address bar of a desktop, the menu or a banner on a phone);
372- // beforeinstallprompt event and shows its own button ([data-install] in the372+ // the page leaves that offer alone. Self-contained: jstest/install.test.mjs
373- // header), which asks the browser to prompt. The button stays hidden when the373+ // evaluates this block alone.
374- // app is already running installed or once it was installed. Self-contained:
375- // jstest/install.test.mjs evaluates this block alone.
376 window.ermiteInstall = (() => {374 window.ermiteInstall = (() => {
377- let deferred = null;
378- const buttons = () => $$('[data-install]');
379- const show = (on) => { for (const b of buttons()) b.hidden = !on; };
380- const installed = () =>
381- !!window.matchMedia?.('(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)').matches ||
382- navigator.standalone === true;
383 const api = {375 const api = {
384 // register installs the service worker; a browser without one, or a376 // register installs the service worker; a browser without one, or a
385 // refusal, leaves the site working as before.377 // refusal, leaves the site working as before.
@@ -387,44 +379,7 @@
387 if (!navigator.serviceWorker) return Promise.resolve(null);379 if (!navigator.serviceWorker) return Promise.resolve(null);
388 return navigator.serviceWorker.register('/-/sw.js', { scope: '/' }).catch(() => null);380 return navigator.serviceWorker.register('/-/sw.js', { scope: '/' }).catch(() => null);
389 },381 },
390- // offer keeps the event the browser sent and shows the button.
391- offer(e) {
392- if (installed()) return;
393- e.preventDefault();
394- deferred = e;
395- show(true);
396- },
397- // prompt asks the browser to show its install dialog. The event works
398- // once: a new one comes if the visitor dismisses the dialog. The button
399- // stays while the dialog is up; once it hides, the focus it held moves
400- // to the search of the header rather than to the body.
401- async prompt() {
402- const e = deferred;
403- if (!e) return '';
404- deferred = null;
405- let outcome = '';
406- try {
407- await e.prompt();
408- outcome = (await e.userChoice).outcome;
409- } catch {
410- outcome = '';
411- }
412- const had = buttons().some((b) => b === document.activeElement);
413- show(false);
414- if (had) document.querySelector('[aria-controls="panel-cmd"]')?.focus?.();
415- return outcome;
416- },
417- done() {
418- deferred = null;
419- show(false);
420- },
421 };382 };
422- addEventListener('beforeinstallprompt', api.offer);
423- addEventListener('appinstalled', api.done);
424- addEventListener('click', (e) => {
425- // pending is the prompt the last click started (its outcome)
426- if (e.target.closest?.('[data-install]')) api.pending = api.prompt();
427- });
428 if (document.readyState === 'complete') api.register();383 if (document.readyState === 'complete') api.register();
429 else addEventListener('load', () => api.register(), { once: true });384 else addEventListener('load', () => api.register(), { once: true });
430 return api;385 return api;
M internal/app/testdata/web/blob-binary.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-code.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-empty.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-image.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-markdown.html +0 -4
@@ -69,10 +69,6 @@
6969 <span class="search-label">Go to…</span>
7070 <kbd aria-hidden="true">ctrl k</kbd>
7171 </button>
72-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
73-<span class="ico i-download" aria-hidden="true">
74-</span>
75-</button>
7672 </div>
7773 </div>
7874 <nav class="tabs" aria-label="Sections">
@@ -69,10 +69,6 @@
69 <span class="search-label">Go to…</span>69 <span class="search-label">Go to…</span>
70 <kbd aria-hidden="true">ctrl k</kbd>70 <kbd aria-hidden="true">ctrl k</kbd>
71 </button>71 </button>
72-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
73-<span class="ico i-download" aria-hidden="true">
74-</span>
75-</button>
76 </div>72 </div>
77 </div>73 </div>
78 <nav class="tabs" aria-label="Sections">74 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-svg.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-text.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-too-large.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/blob-trojan.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-big.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-binary.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-merge.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-modify-split.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-modify.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-rename.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-root.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commit-trojan.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commits-page2.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commits-path.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commits-root.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/commits-small.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/empty.html +0 -4
@@ -51,10 +51,6 @@
5151 <span class="search-label">Go to…</span>
5252 <kbd aria-hidden="true">ctrl k</kbd>
5353 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
5854 </div>
5955 </div>
6056 </header>
@@ -51,10 +51,6 @@
51 <span class="search-label">Go to…</span>51 <span class="search-label">Go to…</span>
52 <kbd aria-hidden="true">ctrl k</kbd>52 <kbd aria-hidden="true">ctrl k</kbd>
53 </button>53 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
58 </div>54 </div>
59 </div>55 </div>
60 </header>56 </header>
M internal/app/testdata/web/home.html +0 -4
@@ -44,10 +44,6 @@
4444 <span class="search-label">Go to…</span>
4545 <kbd aria-hidden="true">ctrl k</kbd>
4646 </button>
47-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
48-<span class="ico i-download" aria-hidden="true">
49-</span>
50-</button>
5147 </div>
5248 </div>
5349 </header>
@@ -44,10 +44,6 @@
44 <span class="search-label">Go to…</span>44 <span class="search-label">Go to…</span>
45 <kbd aria-hidden="true">ctrl k</kbd>45 <kbd aria-hidden="true">ctrl k</kbd>
46 </button>46 </button>
47-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
48-<span class="ico i-download" aria-hidden="true">
49-</span>
50-</button>
51 </div>47 </div>
52 </div>48 </div>
53 </header>49 </header>
M internal/app/testdata/web/not-found-page.html +0 -4
@@ -51,10 +51,6 @@
5151 <span class="search-label">Go to…</span>
5252 <kbd aria-hidden="true">ctrl k</kbd>
5353 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
5854 </div>
5955 </div>
6056 </header>
@@ -51,10 +51,6 @@
51 <span class="search-label">Go to…</span>51 <span class="search-label">Go to…</span>
52 <kbd aria-hidden="true">ctrl k</kbd>52 <kbd aria-hidden="true">ctrl k</kbd>
53 </button>53 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
58 </div>54 </div>
59 </div>55 </div>
60 </header>56 </header>
M internal/app/testdata/web/not-found.html +0 -4
@@ -51,10 +51,6 @@
5151 <span class="search-label">Go to…</span>
5252 <kbd aria-hidden="true">ctrl k</kbd>
5353 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
5854 </div>
5955 </div>
6056 </header>
@@ -51,10 +51,6 @@
51 <span class="search-label">Go to…</span>51 <span class="search-label">Go to…</span>
52 <kbd aria-hidden="true">ctrl k</kbd>52 <kbd aria-hidden="true">ctrl k</kbd>
53 </button>53 </button>
54-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
55-<span class="ico i-download" aria-hidden="true">
56-</span>
57-</button>
58 </div>54 </div>
59 </div>55 </div>
60 </header>56 </header>
M internal/app/testdata/web/refs.html +0 -4
@@ -60,10 +60,6 @@
6060 <span class="search-label">Go to…</span>
6161 <kbd aria-hidden="true">ctrl k</kbd>
6262 </button>
63-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
64-<span class="ico i-download" aria-hidden="true">
65-</span>
66-</button>
6763 </div>
6864 </div>
6965 <nav class="tabs" aria-label="Sections">
@@ -60,10 +60,6 @@
60 <span class="search-label">Go to…</span>60 <span class="search-label">Go to…</span>
61 <kbd aria-hidden="true">ctrl k</kbd>61 <kbd aria-hidden="true">ctrl k</kbd>
62 </button>62 </button>
63-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
64-<span class="ico i-download" aria-hidden="true">
65-</span>
66-</button>
67 </div>63 </div>
68 </div>64 </div>
69 <nav class="tabs" aria-label="Sections">65 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/summary.html +1 -9
@@ -57,10 +57,6 @@
5757 <span class="search-label">Go to…</span>
5858 <kbd aria-hidden="true">ctrl k</kbd>
5959 </button>
60-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
61-<span class="ico i-download" aria-hidden="true">
62-</span>
63-</button>
6460 </div>
6561 </div>
6662 <nav class="tabs" aria-label="Sections">
@@ -153,11 +149,7 @@
153149 </dd>
154150 <dt>latest tag</dt>
155151 <dd class="latest-tag">
156-<a class="tag-name" href="/demo/tree/v0.2.0" title="add main.go">
157-<span class="ico i-tag" aria-hidden="true">
158-</span>v0.2.0</a>
159-<time class="dim" datetime="STAMP" title="STAMP">AGO</time>
160-<a class="all-tags" href="/demo/refs">2 tags</a>
152+<a class="tag-name" href="/demo/tree/v0.2.0" title="add main.go">v0.2.0</a> · <time datetime="STAMP" title="STAMP">AGO</time> · <a class="all-tags" href="/demo/refs">2 tags</a>
161153 </dd>
162154 </dl>
163155 </section>
@@ -57,10 +57,6 @@
57 <span class="search-label">Go to…</span>57 <span class="search-label">Go to…</span>
58 <kbd aria-hidden="true">ctrl k</kbd>58 <kbd aria-hidden="true">ctrl k</kbd>
59 </button>59 </button>
60-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
61-<span class="ico i-download" aria-hidden="true">
62-</span>
63-</button>
64 </div>60 </div>
65 </div>61 </div>
66 <nav class="tabs" aria-label="Sections">62 <nav class="tabs" aria-label="Sections">
@@ -153,11 +149,7 @@
153 </dd>149 </dd>
154 <dt>latest tag</dt>150 <dt>latest tag</dt>
155 <dd class="latest-tag">151 <dd class="latest-tag">
156-<a class="tag-name" href="/demo/tree/v0.2.0" title="add main.go">152+<a class="tag-name" href="/demo/tree/v0.2.0" title="add main.go">v0.2.0</a> · <time datetime="STAMP" title="STAMP">AGO</time> · <a class="all-tags" href="/demo/refs">2 tags</a>
157-<span class="ico i-tag" aria-hidden="true">
158-</span>v0.2.0</a>
159-<time class="dim" datetime="STAMP" title="STAMP">AGO</time>
160-<a class="all-tags" href="/demo/refs">2 tags</a>
161 </dd>153 </dd>
162 </dl>154 </dl>
163 </section>155 </section>
M internal/app/testdata/web/tree-nested.html +0 -4
@@ -69,10 +69,6 @@
6969 <span class="search-label">Go to…</span>
7070 <kbd aria-hidden="true">ctrl k</kbd>
7171 </button>
72-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
73-<span class="ico i-download" aria-hidden="true">
74-</span>
75-</button>
7672 </div>
7773 </div>
7874 <nav class="tabs" aria-label="Sections">
@@ -69,10 +69,6 @@
69 <span class="search-label">Go to…</span>69 <span class="search-label">Go to…</span>
70 <kbd aria-hidden="true">ctrl k</kbd>70 <kbd aria-hidden="true">ctrl k</kbd>
71 </button>71 </button>
72-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
73-<span class="ico i-download" aria-hidden="true">
74-</span>
75-</button>
76 </div>72 </div>
77 </div>73 </div>
78 <nav class="tabs" aria-label="Sections">74 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/tree-root.html +0 -4
@@ -63,10 +63,6 @@
6363 <span class="search-label">Go to…</span>
6464 <kbd aria-hidden="true">ctrl k</kbd>
6565 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
7066 </div>
7167 </div>
7268 <nav class="tabs" aria-label="Sections">
@@ -63,10 +63,6 @@
63 <span class="search-label">Go to…</span>63 <span class="search-label">Go to…</span>
64 <kbd aria-hidden="true">ctrl k</kbd>64 <kbd aria-hidden="true">ctrl k</kbd>
65 </button>65 </button>
66-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
67-<span class="ico i-download" aria-hidden="true">
68-</span>
69-</button>
70 </div>66 </div>
71 </div>67 </div>
72 <nav class="tabs" aria-label="Sections">68 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/tree-slash-ref.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/testdata/web/tree-subdir.html +0 -4
@@ -66,10 +66,6 @@
6666 <span class="search-label">Go to…</span>
6767 <kbd aria-hidden="true">ctrl k</kbd>
6868 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
7369 </div>
7470 </div>
7571 <nav class="tabs" aria-label="Sections">
@@ -66,10 +66,6 @@
66 <span class="search-label">Go to…</span>66 <span class="search-label">Go to…</span>
67 <kbd aria-hidden="true">ctrl k</kbd>67 <kbd aria-hidden="true">ctrl k</kbd>
68 </button>68 </button>
69-<button type="button" class="btn icon" data-install hidden aria-label="Install app" title="install ermite as an app">
70-<span class="ico i-download" aria-hidden="true">
71-</span>
72-</button>
73 </div>69 </div>
74 </div>70 </div>
75 <nav class="tabs" aria-label="Sections">71 <nav class="tabs" aria-label="Sections">
M internal/app/web_mr_test.go +9 -3
@@ -98,7 +98,7 @@ func TestWebMergeRequestPagesRender(t *testing.T) {
9898 // Open one from the compare page.
9999 res := b.form("/proj/merge-requests", token, url.Values{
100100 "source": {"feat/search"}, "target": {"main"}, "title": {"Add <b>search</b>"},
101- "description": {"Finds things.\r\nSee https://example.org/spec) and javascript:alert(1)"},
101+ "description": {"## Summary\r\n\r\nFinds **things** with `Find()`.\r\n\r\n- See https://example.org/spec) and javascript:alert(1)\r\n- [x](javascript:alert(1)) <script>alert(1)</script>"},
102102 })
103103 require.Equal(t, http.StatusSeeOther, res.status, res.body)
104104 assert.Equal(t, "/proj/merge-requests/1", res.hdr.Get("Location"))
@@ -137,9 +137,15 @@ func TestWebMergeRequestPagesRender(t *testing.T) {
137137 assert.Contains(t, mr.body, "package search</td>")
138138 assert.Contains(t, mr.body, "no checks")
139139 assert.Contains(t, mr.body, "fast-forward, squash")
140- assert.Contains(t, mr.body, `<a href="https://example.org/spec" rel="noopener nofollow ugc">https://example.org/spec</a>)`, "the address is linked, not its closing bracket")
140+ // The description is Markdown, rendered as a README: no raw HTML, no
141+ // script URL; its heading ids keep apart from the ids of the page.
142+ assert.Contains(t, mr.body, `<article class="mr-desc prose" aria-label="description" hx-ignore>`)
143+ assert.Contains(t, mr.body, `<h2 id="mr-desc-summary">Summary</h2>`)
144+ assert.Contains(t, mr.body, `<strong>things</strong>`)
145+ assert.Contains(t, mr.body, `<code>Find()</code>`)
146+ assert.Contains(t, mr.body, `<a href="https://example.org/spec"`, "a bare address is linked")
141147 assert.NotContains(t, mr.body, `href="javascript:`)
142- assert.Contains(t, mr.body, "Finds things.\nSee ", "line breaks are kept")
148+ assert.NotContains(t, mr.body, `<script>alert(1)</script>`)
143149 assert.NotContains(t, mr.body, "<form", "an anonymous visitor gets no form")
144150 assert.NotContains(t, mr.body, "ermite mr merge", "nor the merge line")
145151 assert.NotContains(t, mr.body, `id="merge-menu"`)
@@ -98,7 +98,7 @@ func TestWebMergeRequestPagesRender(t *testing.T) {
98 // Open one from the compare page.98 // Open one from the compare page.
99 res := b.form("/proj/merge-requests", token, url.Values{99 res := b.form("/proj/merge-requests", token, url.Values{
100 "source": {"feat/search"}, "target": {"main"}, "title": {"Add <b>search</b>"},100 "source": {"feat/search"}, "target": {"main"}, "title": {"Add <b>search</b>"},
101- "description": {"Finds things.\r\nSee https://example.org/spec) and javascript:alert(1)"},101+ "description": {"## Summary\r\n\r\nFinds **things** with `Find()`.\r\n\r\n- See https://example.org/spec) and javascript:alert(1)\r\n- [x](javascript:alert(1)) <script>alert(1)</script>"},
102 })102 })
103 require.Equal(t, http.StatusSeeOther, res.status, res.body)103 require.Equal(t, http.StatusSeeOther, res.status, res.body)
104 assert.Equal(t, "/proj/merge-requests/1", res.hdr.Get("Location"))104 assert.Equal(t, "/proj/merge-requests/1", res.hdr.Get("Location"))
@@ -137,9 +137,15 @@ func TestWebMergeRequestPagesRender(t *testing.T) {
137 assert.Contains(t, mr.body, "package search</td>")137 assert.Contains(t, mr.body, "package search</td>")
138 assert.Contains(t, mr.body, "no checks")138 assert.Contains(t, mr.body, "no checks")
139 assert.Contains(t, mr.body, "fast-forward, squash")139 assert.Contains(t, mr.body, "fast-forward, squash")
140- assert.Contains(t, mr.body, `<a href="https://example.org/spec" rel="noopener nofollow ugc">https://example.org/spec</a>)`, "the address is linked, not its closing bracket")140+ // The description is Markdown, rendered as a README: no raw HTML, no
141+ // script URL; its heading ids keep apart from the ids of the page.
142+ assert.Contains(t, mr.body, `<article class="mr-desc prose" aria-label="description" hx-ignore>`)
143+ assert.Contains(t, mr.body, `<h2 id="mr-desc-summary">Summary</h2>`)
144+ assert.Contains(t, mr.body, `<strong>things</strong>`)
145+ assert.Contains(t, mr.body, `<code>Find()</code>`)
146+ assert.Contains(t, mr.body, `<a href="https://example.org/spec"`, "a bare address is linked")
141 assert.NotContains(t, mr.body, `href="javascript:`)147 assert.NotContains(t, mr.body, `href="javascript:`)
142- assert.Contains(t, mr.body, "Finds things.\nSee ", "line breaks are kept")148+ assert.NotContains(t, mr.body, `<script>alert(1)</script>`)
143 assert.NotContains(t, mr.body, "<form", "an anonymous visitor gets no form")149 assert.NotContains(t, mr.body, "<form", "an anonymous visitor gets no form")
144 assert.NotContains(t, mr.body, "ermite mr merge", "nor the merge line")150 assert.NotContains(t, mr.body, "ermite mr merge", "nor the merge line")
145 assert.NotContains(t, mr.body, `id="merge-menu"`)151 assert.NotContains(t, mr.body, `id="merge-menu"`)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 43

↑↓ moveenter openesc close