detached 0a9e349

#6 feat(web): review page polish and home page ordered by last activity

state
merged · 4ce8534 · squash
branch
feat/mr-header-card → main
opened
bnema ·
updated

Review page and home page polish, plus "last activity" ordering of the repositories.

Merge request page

  • Title, facts and description in one card; the header a shade lighter than the description. Issues share it.
  • Unified / Split / Collapse all in one view menu (the existing details.menu component); u, d and x still work, escape closes menus on every page and the focus goes back to the menu button.
  • Wide mode on every page with w (listed in ?), kept in localStorage; store.js loads without defer and sets it before the first paint.
  • Hunk headers and hidden-line rows are quieter (background and border), text keeps its contrast.
  • A shift + click range is one block (one border, none between its lines, per side in split); the form title names the whole range (a.go:21-149); lines loaded later from a gap inside the range are selected too.

Home page

  • Inbox button next to the logo, home page only, with a mailbox icon (Lucide) and a darker count badge.
  • Default order is the last activity: push (incl. merge), merge request opened / merged / closed / ready, comment on a merge request, issue opened / approved / closed / reopened / commented. Moderation (submissions, rejections) stays owner-only and does not count.
  • The row of a repository with activity moves to the top live (activity order only; CI updates do not move it).

Storage

  • Repo.ActiveAt (storage proto field 8; falls back to the later of pushed and created).
  • RepoMetaStore.Update is replaced by Mutate: a compare-and-swap on the version read, retried up to 8 times. The previous Update checked the version read at write time, so a read-modify-write could overwrite a concurrent change (e.g. a visibility change).

No change to ermite-api.

Checks: go vet ./..., go test ./..., go test -race on usecase and kvstore, JS tests (160), golden pages refreshed, manual checks on the dev server. Reviewed by Go and JS reviewers; findings fixed.

CommitSubjectAuthorDateSignatureStatus
0a9e349test: run the activity store test outside the usecase package and its home row subtests in parallelbriceGPG Verified
9ca7c68fix(repos): mutate metadata atomically and record approved issue activitybriceGPG Verified
32e9fe7fix(web): match loaded lines to a selection by file key, keep the focus on a closing menu, close menus with escape on every page and restore the hunk header contrastbriceGPG Verified
4277264feat(web): order the home page by last activity and move repositories up livebriceGPG Verified
4fc291efeat(web): move the inbox button of the home page next to the logo, with a mailbox icon and a darker count badgebriceGPG Verified
5f6d2c6test(app): refresh the web golden pages for the view menu, the w shortcut and the store scriptbriceGPG Verified
a772c1bfix(web): a selected line range is one block, its title names the whole range and its hidden lines stay selected once loadedbriceGPG Verified
502935erefactor(web): drop the Wide button of the diff bar, the w shortcut covers itbriceGPG Verified
a1f8e85feat(web): make the wide mode a global w shortcut, set before the first paint, and tighten the merge request headerbriceGPG Verified
fcc7703feat(web): one merge request card, a diff view menu, a wide diff mode and quieter hunk rowsbriceGPG Verified

Checks 4

92 files · +2426 -1392
4/4
M gen/ermite/storage/repo.pb.go +22 -11 generated file: collapsed
M internal/adapters/kvstore/issues_test.go +4 -2
@@ -258,13 +258,15 @@ func TestRepoSettingsKeepTheIssuesMode(t *testing.T) {
258258 assert.Equal(t, domain.IssuesOff, got.Settings.Issues)
259259 for _, m := range []domain.IssuesMode{domain.IssuesOwner, domain.IssuesPublic, domain.IssuesOff} {
260260 got.Settings.Issues = m
261- require.NoError(t, s.Update(ctx, got))
261+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
262+ require.NoError(t, err)
262263 again, err := s.Get(ctx, n)
263264 require.NoError(t, err)
264265 assert.Equal(t, m, again.Settings.Issues)
265266 }
266267 got.Settings.Issues = "everyone"
267- assert.ErrorIs(t, s.Update(ctx, got), domain.ErrInvalid)
268+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
269+ assert.ErrorIs(t, err, domain.ErrInvalid)
268270 }
269271
270272 // TestSchema4UpgradesTheTokensWithAllScopes: the tokens that held every
@@ -258,13 +258,15 @@ func TestRepoSettingsKeepTheIssuesMode(t *testing.T) {
258 assert.Equal(t, domain.IssuesOff, got.Settings.Issues)258 assert.Equal(t, domain.IssuesOff, got.Settings.Issues)
259 for _, m := range []domain.IssuesMode{domain.IssuesOwner, domain.IssuesPublic, domain.IssuesOff} {259 for _, m := range []domain.IssuesMode{domain.IssuesOwner, domain.IssuesPublic, domain.IssuesOff} {
260 got.Settings.Issues = m260 got.Settings.Issues = m
261- require.NoError(t, s.Update(ctx, got))261+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
262+ require.NoError(t, err)
262 again, err := s.Get(ctx, n)263 again, err := s.Get(ctx, n)
263 require.NoError(t, err)264 require.NoError(t, err)
264 assert.Equal(t, m, again.Settings.Issues)265 assert.Equal(t, m, again.Settings.Issues)
265 }266 }
266 got.Settings.Issues = "everyone"267 got.Settings.Issues = "everyone"
267- assert.ErrorIs(t, s.Update(ctx, got), domain.ErrInvalid)268+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
269+ assert.ErrorIs(t, err, domain.ErrInvalid)
268 }270 }
269 271
270 // TestSchema4UpgradesTheTokensWithAllScopes: the tokens that held every272 // TestSchema4UpgradesTheTokensWithAllScopes: the tokens that held every
M internal/adapters/kvstore/mergerequests_test.go +4 -2
@@ -442,13 +442,15 @@ func TestRepoSettings(t *testing.T) {
442442 assert.Equal(t, domain.DefaultRepoSettings(), got.Settings)
443443
444444 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false, Issues: domain.IssuesOwner}
445- require.NoError(t, s.Update(ctx, got))
445+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
446+ require.NoError(t, err)
446447 again, err := s.Get(ctx, n)
447448 require.NoError(t, err)
448449 assert.Equal(t, got.Settings, again.Settings)
449450
450451 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{"rebase"}}
451- assert.ErrorIs(t, s.Update(ctx, got), domain.ErrInvalid)
452+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
453+ assert.ErrorIs(t, err, domain.ErrInvalid)
452454 }
453455
454456 // TestRepoWithoutStoredSettingsReadsTheDefaults: a repository stored before
@@ -442,13 +442,15 @@ func TestRepoSettings(t *testing.T) {
442 assert.Equal(t, domain.DefaultRepoSettings(), got.Settings)442 assert.Equal(t, domain.DefaultRepoSettings(), got.Settings)
443 443
444 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false, Issues: domain.IssuesOwner}444 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false, Issues: domain.IssuesOwner}
445- require.NoError(t, s.Update(ctx, got))445+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
446+ require.NoError(t, err)
446 again, err := s.Get(ctx, n)447 again, err := s.Get(ctx, n)
447 require.NoError(t, err)448 require.NoError(t, err)
448 assert.Equal(t, got.Settings, again.Settings)449 assert.Equal(t, got.Settings, again.Settings)
449 450
450 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{"rebase"}}451 got.Settings = domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{"rebase"}}
451- assert.ErrorIs(t, s.Update(ctx, got), domain.ErrInvalid)452+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Settings = got.Settings; return true, nil })
453+ assert.ErrorIs(t, err, domain.ErrInvalid)
452 }454 }
453 455
454 // TestRepoWithoutStoredSettingsReadsTheDefaults: a repository stored before456 // TestRepoWithoutStoredSettingsReadsTheDefaults: a repository stored before
M internal/adapters/kvstore/repos.go +44 -22
@@ -64,31 +64,51 @@ func (s *Store) List(ctx context.Context) ([]domain.Repo, error) {
6464 return repos, nil
6565 }
6666
67-// Update replaces the stored repository. It returns domain.ErrNotFound if
68-// there is none and domain.ErrConflict if another write changed it since it
69-// was read.
67+const repoMutationTries = 8
68+
69+// Mutate applies a retry-safe mutation under the version it read.
7070 //
71-//hexcheck:ignore suspicious-business-logic-in-adapter port method name only
72-func (s *Store) Update(ctx context.Context, repo domain.Repo) error {
73- val, err := encodeRepo(repo)
74- if err != nil {
75- return err
76- }
77- key := repoKey(repo.Name)
78- item, ok := s.db.Get(ctx, key)
79- if !ok {
80- return domain.ErrNotFound
81- }
82- var b kv.Batch
83- b.RequireVersion(key, item.Version)
84- b.Put(key, val)
85- if _, err := s.db.Apply(ctx, &b); err != nil {
86- if errors.Is(err, kv.ErrConflict) {
87- return domain.ErrConflict
71+//hexcheck:ignore suspicious-business-logic-in-adapter optimistic concurrency is a storage concern
72+func (s *Store) Mutate(ctx context.Context, name domain.RepoName, fn func(*domain.Repo) (bool, error)) (domain.Repo, error) {
73+ key := repoKey(name)
74+ for range repoMutationTries {
75+ if err := ctx.Err(); err != nil {
76+ return domain.Repo{}, err
77+ }
78+ item, ok := s.db.Get(ctx, key)
79+ if !ok {
80+ return domain.Repo{}, domain.ErrNotFound
8881 }
89- return fmt.Errorf("update repository %q: %w", repo.Name, err)
82+ repo, err := decodeRepo(item.Value)
83+ if err != nil {
84+ return domain.Repo{}, err
85+ }
86+ changed, err := fn(&repo)
87+ if err != nil {
88+ return domain.Repo{}, err
89+ }
90+ if repo.Name != name {
91+ return domain.Repo{}, fmt.Errorf("mutate repository name: %w", domain.ErrInvalidName)
92+ }
93+ if !changed {
94+ return decodeRepo(item.Value)
95+ }
96+ val, err := encodeRepo(repo)
97+ if err != nil {
98+ return domain.Repo{}, err
99+ }
100+ var b kv.Batch
101+ b.RequireVersion(key, item.Version)
102+ b.Put(key, val)
103+ if _, err := s.db.Apply(ctx, &b); err != nil {
104+ if errors.Is(err, kv.ErrConflict) {
105+ continue
106+ }
107+ return domain.Repo{}, fmt.Errorf("mutate repository %q: %w", name, err)
108+ }
109+ return decodeRepo(val)
90110 }
91- return nil
111+ return domain.Repo{}, domain.ErrConflict
92112 }
93113
94114 // guardRepoKey makes the batch depend on the repository: it requires the
@@ -208,6 +228,7 @@ func encodeRepo(r domain.Repo) ([]byte, error) {
208228 Visibility: vis,
209229 CreatedAt: encodeTime(r.CreatedAt),
210230 PushedAt: encodeTime(r.PushedAt),
231+ ActiveAt: encodeTime(r.ActiveAt),
211232 Settings: pbSettings,
212233 }
213234 return mustMarshal(pb), nil
@@ -229,6 +250,7 @@ func decodeRepo(val []byte) (domain.Repo, error) {
229250 Visibility: decodeVisibility(pb.GetVisibility()),
230251 CreatedAt: decodeTime(pb.GetCreatedAt()),
231252 PushedAt: decodeTime(pb.GetPushedAt()),
253+ ActiveAt: decodeTime(pb.GetActiveAt()),
232254 Settings: decodeSettings(pb.GetSettings()),
233255 }, nil
234256 }
@@ -64,31 +64,51 @@ func (s *Store) List(ctx context.Context) ([]domain.Repo, error) {
64 return repos, nil64 return repos, nil
65 }65 }
66 66
67-// Update replaces the stored repository. It returns domain.ErrNotFound if67+const repoMutationTries = 8
68-// there is none and domain.ErrConflict if another write changed it since it68+
69-// was read.69+// Mutate applies a retry-safe mutation under the version it read.
70 //70 //
71-//hexcheck:ignore suspicious-business-logic-in-adapter port method name only71+//hexcheck:ignore suspicious-business-logic-in-adapter optimistic concurrency is a storage concern
72-func (s *Store) Update(ctx context.Context, repo domain.Repo) error {72+func (s *Store) Mutate(ctx context.Context, name domain.RepoName, fn func(*domain.Repo) (bool, error)) (domain.Repo, error) {
73- val, err := encodeRepo(repo)73+ key := repoKey(name)
74- if err != nil {74+ for range repoMutationTries {
75- return err75+ if err := ctx.Err(); err != nil {
76- }76+ return domain.Repo{}, err
77- key := repoKey(repo.Name)77+ }
78- item, ok := s.db.Get(ctx, key)78+ item, ok := s.db.Get(ctx, key)
79- if !ok {79+ if !ok {
80- return domain.ErrNotFound80+ return domain.Repo{}, domain.ErrNotFound
81- }
82- var b kv.Batch
83- b.RequireVersion(key, item.Version)
84- b.Put(key, val)
85- if _, err := s.db.Apply(ctx, &b); err != nil {
86- if errors.Is(err, kv.ErrConflict) {
87- return domain.ErrConflict
88 }81 }
89- return fmt.Errorf("update repository %q: %w", repo.Name, err)82+ repo, err := decodeRepo(item.Value)
83+ if err != nil {
84+ return domain.Repo{}, err
85+ }
86+ changed, err := fn(&repo)
87+ if err != nil {
88+ return domain.Repo{}, err
89+ }
90+ if repo.Name != name {
91+ return domain.Repo{}, fmt.Errorf("mutate repository name: %w", domain.ErrInvalidName)
92+ }
93+ if !changed {
94+ return decodeRepo(item.Value)
95+ }
96+ val, err := encodeRepo(repo)
97+ if err != nil {
98+ return domain.Repo{}, err
99+ }
100+ var b kv.Batch
101+ b.RequireVersion(key, item.Version)
102+ b.Put(key, val)
103+ if _, err := s.db.Apply(ctx, &b); err != nil {
104+ if errors.Is(err, kv.ErrConflict) {
105+ continue
106+ }
107+ return domain.Repo{}, fmt.Errorf("mutate repository %q: %w", name, err)
108+ }
109+ return decodeRepo(val)
90 }110 }
91- return nil111+ return domain.Repo{}, domain.ErrConflict
92 }112 }
93 113
94 // guardRepoKey makes the batch depend on the repository: it requires the114 // guardRepoKey makes the batch depend on the repository: it requires the
@@ -208,6 +228,7 @@ func encodeRepo(r domain.Repo) ([]byte, error) {
208 Visibility: vis,228 Visibility: vis,
209 CreatedAt: encodeTime(r.CreatedAt),229 CreatedAt: encodeTime(r.CreatedAt),
210 PushedAt: encodeTime(r.PushedAt),230 PushedAt: encodeTime(r.PushedAt),
231+ ActiveAt: encodeTime(r.ActiveAt),
211 Settings: pbSettings,232 Settings: pbSettings,
212 }233 }
213 return mustMarshal(pb), nil234 return mustMarshal(pb), nil
@@ -229,6 +250,7 @@ func decodeRepo(val []byte) (domain.Repo, error) {
229 Visibility: decodeVisibility(pb.GetVisibility()),250 Visibility: decodeVisibility(pb.GetVisibility()),
230 CreatedAt: decodeTime(pb.GetCreatedAt()),251 CreatedAt: decodeTime(pb.GetCreatedAt()),
231 PushedAt: decodeTime(pb.GetPushedAt()),252 PushedAt: decodeTime(pb.GetPushedAt()),
253+ ActiveAt: decodeTime(pb.GetActiveAt()),
232 Settings: decodeSettings(pb.GetSettings()),254 Settings: decodeSettings(pb.GetSettings()),
233 }, nil255 }, nil
234 }256 }
A internal/adapters/kvstore/repos_mutate_test.go +87 -0
@@ -0,0 +1,87 @@
1+// SPDX-License-Identifier: AGPL-3.0-or-later
2+
3+package kvstore_test
4+
5+import (
6+ "errors"
7+ "testing"
8+ "time"
9+
10+ "github.com/stretchr/testify/require"
11+
12+ "bnema.dev/ermite/internal/domain"
13+)
14+
15+func TestRepoMutateInterleavedWrites(t *testing.T) {
16+ ctx := t.Context()
17+ s := openStore(t, t.TempDir())
18+ n := name(t, "proj")
19+ original := domain.Repo{Name: n, Visibility: domain.VisibilityPublic, CreatedAt: created}
20+ require.NoError(t, s.Create(ctx, original))
21+ later := created.Add(2 * time.Hour)
22+ calls := 0
23+ got, err := s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) {
24+ calls++
25+ // Test-only interleaving: inject a committed write after the outer read.
26+ if calls == 1 {
27+ _, err := s.Mutate(ctx, n, func(current *domain.Repo) (bool, error) {
28+ current.Visibility = domain.VisibilityPrivate
29+ current.ActiveAt = later
30+ current.PushedAt = later
31+ return true, nil
32+ })
33+ require.NoError(t, err)
34+ }
35+ r.Description = "updated"
36+ at := created.Add(time.Hour)
37+ if at.After(r.ActiveAt) {
38+ r.ActiveAt = at
39+ }
40+ if at.After(r.PushedAt) {
41+ r.PushedAt = at
42+ }
43+ return true, nil
44+ })
45+ require.NoError(t, err)
46+ require.Equal(t, 2, calls)
47+ require.Equal(t, domain.VisibilityPrivate, got.Visibility)
48+ require.Equal(t, "updated", got.Description)
49+ require.Equal(t, later, got.ActiveAt)
50+ require.Equal(t, later, got.PushedAt)
51+ stored, err := s.Get(ctx, n)
52+ require.NoError(t, err)
53+ require.Equal(t, got, stored)
54+}
55+
56+func TestRepoMutateContracts(t *testing.T) {
57+ ctx := t.Context()
58+ s := openStore(t, t.TempDir())
59+ n := name(t, "proj")
60+ require.NoError(t, s.Create(ctx, domain.Repo{Name: n, Visibility: domain.VisibilityPublic, CreatedAt: created}))
61+ original, err := s.Get(ctx, n)
62+ require.NoError(t, err)
63+ boom := errors.New("callback failed")
64+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Description = "discard"; return true, boom })
65+ require.ErrorIs(t, err, boom)
66+ got, err := s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Description = "discard"; return false, nil })
67+ require.NoError(t, err)
68+ require.Equal(t, original, got)
69+ for _, changed := range []bool{false, true} {
70+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Name = name(t, "other"); return changed, nil })
71+ require.ErrorIs(t, err, domain.ErrInvalidName)
72+ }
73+ got, err = s.Get(ctx, n)
74+ require.NoError(t, err)
75+ require.Equal(t, original, got)
76+ calls := 0
77+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) {
78+ calls++
79+ _, err := s.Mutate(ctx, n, func(current *domain.Repo) (bool, error) { current.Description = "concurrent"; return true, nil })
80+ require.NoError(t, err)
81+ return true, nil
82+ })
83+ require.ErrorIs(t, err, domain.ErrConflict)
84+ require.Equal(t, 8, calls)
85+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { require.NoError(t, s.Delete(ctx, n)); return true, nil })
86+ require.ErrorIs(t, err, domain.ErrNotFound)
87+}
@@ -0,0 +1,87 @@
1+// SPDX-License-Identifier: AGPL-3.0-or-later
2+
3+package kvstore_test
4+
5+import (
6+ "errors"
7+ "testing"
8+ "time"
9+
10+ "github.com/stretchr/testify/require"
11+
12+ "bnema.dev/ermite/internal/domain"
13+)
14+
15+func TestRepoMutateInterleavedWrites(t *testing.T) {
16+ ctx := t.Context()
17+ s := openStore(t, t.TempDir())
18+ n := name(t, "proj")
19+ original := domain.Repo{Name: n, Visibility: domain.VisibilityPublic, CreatedAt: created}
20+ require.NoError(t, s.Create(ctx, original))
21+ later := created.Add(2 * time.Hour)
22+ calls := 0
23+ got, err := s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) {
24+ calls++
25+ // Test-only interleaving: inject a committed write after the outer read.
26+ if calls == 1 {
27+ _, err := s.Mutate(ctx, n, func(current *domain.Repo) (bool, error) {
28+ current.Visibility = domain.VisibilityPrivate
29+ current.ActiveAt = later
30+ current.PushedAt = later
31+ return true, nil
32+ })
33+ require.NoError(t, err)
34+ }
35+ r.Description = "updated"
36+ at := created.Add(time.Hour)
37+ if at.After(r.ActiveAt) {
38+ r.ActiveAt = at
39+ }
40+ if at.After(r.PushedAt) {
41+ r.PushedAt = at
42+ }
43+ return true, nil
44+ })
45+ require.NoError(t, err)
46+ require.Equal(t, 2, calls)
47+ require.Equal(t, domain.VisibilityPrivate, got.Visibility)
48+ require.Equal(t, "updated", got.Description)
49+ require.Equal(t, later, got.ActiveAt)
50+ require.Equal(t, later, got.PushedAt)
51+ stored, err := s.Get(ctx, n)
52+ require.NoError(t, err)
53+ require.Equal(t, got, stored)
54+}
55+
56+func TestRepoMutateContracts(t *testing.T) {
57+ ctx := t.Context()
58+ s := openStore(t, t.TempDir())
59+ n := name(t, "proj")
60+ require.NoError(t, s.Create(ctx, domain.Repo{Name: n, Visibility: domain.VisibilityPublic, CreatedAt: created}))
61+ original, err := s.Get(ctx, n)
62+ require.NoError(t, err)
63+ boom := errors.New("callback failed")
64+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Description = "discard"; return true, boom })
65+ require.ErrorIs(t, err, boom)
66+ got, err := s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Description = "discard"; return false, nil })
67+ require.NoError(t, err)
68+ require.Equal(t, original, got)
69+ for _, changed := range []bool{false, true} {
70+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { r.Name = name(t, "other"); return changed, nil })
71+ require.ErrorIs(t, err, domain.ErrInvalidName)
72+ }
73+ got, err = s.Get(ctx, n)
74+ require.NoError(t, err)
75+ require.Equal(t, original, got)
76+ calls := 0
77+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) {
78+ calls++
79+ _, err := s.Mutate(ctx, n, func(current *domain.Repo) (bool, error) { current.Description = "concurrent"; return true, nil })
80+ require.NoError(t, err)
81+ return true, nil
82+ })
83+ require.ErrorIs(t, err, domain.ErrConflict)
84+ require.Equal(t, 8, calls)
85+ _, err = s.Mutate(ctx, n, func(r *domain.Repo) (bool, error) { require.NoError(t, s.Delete(ctx, n)); return true, nil })
86+ require.ErrorIs(t, err, domain.ErrNotFound)
87+}
M internal/adapters/kvstore/store_test.go +8 -4
@@ -43,7 +43,7 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
4343 s := openStore(t, t.TempDir())
4444
4545 b := domain.Repo{Name: name(t, "b"), Description: "second", Topics: []string{"cli", "go"}, Visibility: domain.VisibilityPublic, CreatedAt: created, Settings: domain.DefaultRepoSettings()}
46- a := domain.Repo{Name: name(t, "a"), Visibility: domain.VisibilityPrivate, CreatedAt: created, PushedAt: created.Add(time.Hour), Settings: domain.DefaultRepoSettings()}
46+ a := domain.Repo{Name: name(t, "a"), Visibility: domain.VisibilityPrivate, CreatedAt: created, PushedAt: created.Add(time.Hour), ActiveAt: created.Add(2 * time.Hour), Settings: domain.DefaultRepoSettings()}
4747 require.NoError(t, s.Create(ctx, b))
4848 require.NoError(t, s.Create(ctx, a))
4949
@@ -54,6 +54,7 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
5454 require.NoError(t, err)
5555 assert.Equal(t, a, got)
5656 assert.True(t, got.PushedAt.Equal(a.PushedAt))
57+ assert.True(t, got.ActiveAt.Equal(a.ActiveAt))
5758
5859 list, err := s.List(ctx)
5960 require.NoError(t, err)
@@ -65,13 +66,15 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
6566 b.Description = "changed"
6667 b.Topics = []string{"forge"}
6768 b.Visibility = domain.VisibilityPrivate
68- require.NoError(t, s.Update(ctx, b))
69+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { *r = b; return true, nil })
70+ require.NoError(t, err)
6971 got, err = s.Get(ctx, b.Name)
7072 require.NoError(t, err)
7173 assert.Equal(t, b, got)
7274
7375 b.Topics = nil
74- require.NoError(t, s.Update(ctx, b))
76+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { *r = b; return true, nil })
77+ require.NoError(t, err)
7578 got, err = s.Get(ctx, b.Name)
7679 require.NoError(t, err)
7780 assert.Nil(t, got.Topics, "cleared topics read back as nil")
@@ -80,7 +83,8 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
8083 _, err = s.Get(ctx, b.Name)
8184 assert.ErrorIs(t, err, domain.ErrNotFound)
8285 require.NoError(t, s.Delete(ctx, b.Name), "deleting a missing repository is not an error")
83- assert.ErrorIs(t, s.Update(ctx, b), domain.ErrNotFound)
86+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { return true, nil })
87+ assert.ErrorIs(t, err, domain.ErrNotFound)
8488
8589 _, err = s.Get(ctx, name(t, "never"))
8690 assert.ErrorIs(t, err, domain.ErrNotFound)
@@ -43,7 +43,7 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
43 s := openStore(t, t.TempDir())43 s := openStore(t, t.TempDir())
44 44
45 b := domain.Repo{Name: name(t, "b"), Description: "second", Topics: []string{"cli", "go"}, Visibility: domain.VisibilityPublic, CreatedAt: created, Settings: domain.DefaultRepoSettings()}45 b := domain.Repo{Name: name(t, "b"), Description: "second", Topics: []string{"cli", "go"}, Visibility: domain.VisibilityPublic, CreatedAt: created, Settings: domain.DefaultRepoSettings()}
46- a := domain.Repo{Name: name(t, "a"), Visibility: domain.VisibilityPrivate, CreatedAt: created, PushedAt: created.Add(time.Hour), Settings: domain.DefaultRepoSettings()}46+ a := domain.Repo{Name: name(t, "a"), Visibility: domain.VisibilityPrivate, CreatedAt: created, PushedAt: created.Add(time.Hour), ActiveAt: created.Add(2 * time.Hour), Settings: domain.DefaultRepoSettings()}
47 require.NoError(t, s.Create(ctx, b))47 require.NoError(t, s.Create(ctx, b))
48 require.NoError(t, s.Create(ctx, a))48 require.NoError(t, s.Create(ctx, a))
49 49
@@ -54,6 +54,7 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
54 require.NoError(t, err)54 require.NoError(t, err)
55 assert.Equal(t, a, got)55 assert.Equal(t, a, got)
56 assert.True(t, got.PushedAt.Equal(a.PushedAt))56 assert.True(t, got.PushedAt.Equal(a.PushedAt))
57+ assert.True(t, got.ActiveAt.Equal(a.ActiveAt))
57 58
58 list, err := s.List(ctx)59 list, err := s.List(ctx)
59 require.NoError(t, err)60 require.NoError(t, err)
@@ -65,13 +66,15 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
65 b.Description = "changed"66 b.Description = "changed"
66 b.Topics = []string{"forge"}67 b.Topics = []string{"forge"}
67 b.Visibility = domain.VisibilityPrivate68 b.Visibility = domain.VisibilityPrivate
68- require.NoError(t, s.Update(ctx, b))69+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { *r = b; return true, nil })
70+ require.NoError(t, err)
69 got, err = s.Get(ctx, b.Name)71 got, err = s.Get(ctx, b.Name)
70 require.NoError(t, err)72 require.NoError(t, err)
71 assert.Equal(t, b, got)73 assert.Equal(t, b, got)
72 74
73 b.Topics = nil75 b.Topics = nil
74- require.NoError(t, s.Update(ctx, b))76+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { *r = b; return true, nil })
77+ require.NoError(t, err)
75 got, err = s.Get(ctx, b.Name)78 got, err = s.Get(ctx, b.Name)
76 require.NoError(t, err)79 require.NoError(t, err)
77 assert.Nil(t, got.Topics, "cleared topics read back as nil")80 assert.Nil(t, got.Topics, "cleared topics read back as nil")
@@ -80,7 +83,8 @@ func TestCreateGetListUpdateDelete(t *testing.T) {
80 _, err = s.Get(ctx, b.Name)83 _, err = s.Get(ctx, b.Name)
81 assert.ErrorIs(t, err, domain.ErrNotFound)84 assert.ErrorIs(t, err, domain.ErrNotFound)
82 require.NoError(t, s.Delete(ctx, b.Name), "deleting a missing repository is not an error")85 require.NoError(t, s.Delete(ctx, b.Name), "deleting a missing repository is not an error")
83- assert.ErrorIs(t, s.Update(ctx, b), domain.ErrNotFound)86+ _, err = s.Mutate(ctx, b.Name, func(r *domain.Repo) (bool, error) { return true, nil })
87+ assert.ErrorIs(t, err, domain.ErrNotFound)
84 88
85 _, err = s.Get(ctx, name(t, "never"))89 _, err = s.Get(ctx, name(t, "never"))
86 assert.ErrorIs(t, err, domain.ErrNotFound)90 assert.ErrorIs(t, err, domain.ErrNotFound)
M internal/adapters/web/components.templ +2 -2
@@ -37,7 +37,7 @@ templ CloneBlock(c Clone) {
3737 // right its figures and CI state over its newest commits. Its id is the
3838 // target of SSE swaps; the name link comes first, `enter` follows it.
3939 templ HomeRowView(r HomeRow) {
40- <li id={ r.ID } class="repo" data-cursor?={ r.Cursor }>
40+ <li id={ r.ID } class="repo" data-cursor?={ r.Cursor } data-activity?={ r.Fresh }>
4141 <div class="repo-main">
4242 <h2 class="repo-name">
4343 <a href={ templ.SafeURL(r.Href) }>{ r.Name }</a>
@@ -45,7 +45,7 @@ templ HomeRowView(r HomeRow) {
4545 <span class="pill">private</span>
4646 }
4747 if r.Fresh {
48- <span class="pill new">new push</span>
48+ <span class="pill new">new activity</span>
4949 }
5050 </h2>
5151 if r.Desc != "" {
@@ -37,7 +37,7 @@ templ CloneBlock(c Clone) {
37 // right its figures and CI state over its newest commits. Its id is the37 // right its figures and CI state over its newest commits. Its id is the
38 // target of SSE swaps; the name link comes first, `enter` follows it.38 // target of SSE swaps; the name link comes first, `enter` follows it.
39 templ HomeRowView(r HomeRow) {39 templ HomeRowView(r HomeRow) {
40- <li id={ r.ID } class="repo" data-cursor?={ r.Cursor }>40+ <li id={ r.ID } class="repo" data-cursor?={ r.Cursor } data-activity?={ r.Fresh }>
41 <div class="repo-main">41 <div class="repo-main">
42 <h2 class="repo-name">42 <h2 class="repo-name">
43 <a href={ templ.SafeURL(r.Href) }>{ r.Name }</a>43 <a href={ templ.SafeURL(r.Href) }>{ r.Name }</a>
@@ -45,7 +45,7 @@ templ HomeRowView(r HomeRow) {
45 <span class="pill">private</span>45 <span class="pill">private</span>
46 }46 }
47 if r.Fresh {47 if r.Fresh {
48- <span class="pill new">new push</span>48+ <span class="pill new">new activity</span>
49 }49 }
50 </h2>50 </h2>
51 if r.Desc != "" {51 if r.Desc != "" {
M internal/adapters/web/components_templ.go +119 -113 generated file: collapsed
M internal/adapters/web/diff.templ +22 -4
@@ -72,9 +72,7 @@ templ Commit(l Layout, p CommitPage) {
7272 <div class="diff-tools" role="group" aria-label="Diff view">
7373 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
7474 <span class="grow"></span>
75- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)
76- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
77- @collapseButton()
75+ @diffViewMenu(p.DiffView)
7876 </div>
7977 if p.Invisible {
8078 <p class="notice">
@@ -112,6 +110,26 @@ templ Commit(l Layout, p CommitPage) {
112110 }
113111 }
114112
113+// diffViewMenu is the layout of the diff (unified, the default, or split) and
114+// the fold of its files, in one menu: a <details> that works without scripts;
115+// u, d and x still act without opening it. Its button names the layout shown.
116+templ diffViewMenu(p DiffView) {
117+ <details class="menu vmenu">
118+ <summary class="btn" aria-label="Diff view">
119+ if p.Both {
120+ <span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>
121+ } else {
122+ { viewLabel(p.View) }
123+ }
124+ </summary>
125+ <div class="menu-pop" role="group" aria-label="Diff view">
126+ @viewLink(p, "unified", "Unified", "u", p.UnifiedHref)
127+ @viewLink(p, "split", "Split", "d", p.SplitHref)
128+ @collapseButton()
129+ </div>
130+ </details>
131+}
132+
115133 // viewLink is a button of the diff tools. It is a link, so that the split
116134 // layout works without JavaScript; with it, and when both layouts are in the
117135 // page, a click only flips the layout.
@@ -203,7 +221,7 @@ templ DiffFileView(f DiffFile, p DiffView) {
203221 <details
204222 class={ "dfile", "lnw-" + itoa(f.Digits) }
205223 id={ f.ID }
206- data-file
224+ data-file={ f.Key }
207225 if f.Open {
208226 open
209227 }
@@ -72,9 +72,7 @@ templ Commit(l Layout, p CommitPage) {
72 <div class="diff-tools" role="group" aria-label="Diff view">72 <div class="diff-tools" role="group" aria-label="Diff view">
73 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>73 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
74 <span class="grow"></span>74 <span class="grow"></span>
75- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)75+ @diffViewMenu(p.DiffView)
76- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
77- @collapseButton()
78 </div>76 </div>
79 if p.Invisible {77 if p.Invisible {
80 <p class="notice">78 <p class="notice">
@@ -112,6 +110,26 @@ templ Commit(l Layout, p CommitPage) {
112 }110 }
113 }111 }
114 112
113+// diffViewMenu is the layout of the diff (unified, the default, or split) and
114+// the fold of its files, in one menu: a <details> that works without scripts;
115+// u, d and x still act without opening it. Its button names the layout shown.
116+templ diffViewMenu(p DiffView) {
117+ <details class="menu vmenu">
118+ <summary class="btn" aria-label="Diff view">
119+ if p.Both {
120+ <span hx-live="this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'">{ viewLabel(p.View) }</span>
121+ } else {
122+ { viewLabel(p.View) }
123+ }
124+ </summary>
125+ <div class="menu-pop" role="group" aria-label="Diff view">
126+ @viewLink(p, "unified", "Unified", "u", p.UnifiedHref)
127+ @viewLink(p, "split", "Split", "d", p.SplitHref)
128+ @collapseButton()
129+ </div>
130+ </details>
131+}
132+
115 // viewLink is a button of the diff tools. It is a link, so that the split133 // viewLink is a button of the diff tools. It is a link, so that the split
116 // layout works without JavaScript; with it, and when both layouts are in the134 // layout works without JavaScript; with it, and when both layouts are in the
117 // page, a click only flips the layout.135 // page, a click only flips the layout.
@@ -203,7 +221,7 @@ templ DiffFileView(f DiffFile, p DiffView) {
203 <details221 <details
204 class={ "dfile", "lnw-" + itoa(f.Digits) }222 class={ "dfile", "lnw-" + itoa(f.Digits) }
205 id={ f.ID }223 id={ f.ID }
206- data-file224+ data-file={ f.Key }
207 if f.Open {225 if f.Open {
208 open226 open
209 }227 }
M internal/adapters/web/diff_templ.go +523 -437
@@ -359,15 +359,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
359359 if templ_7745c5c3_Err != nil {
360360 return templ_7745c5c3_Err
361361 }
362- templ_7745c5c3_Err = viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref).Render(ctx, templ_7745c5c3_Buffer)
363- if templ_7745c5c3_Err != nil {
364- return templ_7745c5c3_Err
365- }
366- templ_7745c5c3_Err = viewLink(p.DiffView, "split", "Split", "d", p.SplitHref).Render(ctx, templ_7745c5c3_Buffer)
367- if templ_7745c5c3_Err != nil {
368- return templ_7745c5c3_Err
369- }
370- templ_7745c5c3_Err = collapseButton().Render(ctx, templ_7745c5c3_Buffer)
362+ templ_7745c5c3_Err = diffViewMenu(p.DiffView).Render(ctx, templ_7745c5c3_Buffer)
371363 if templ_7745c5c3_Err != nil {
372364 return templ_7745c5c3_Err
373365 }
@@ -393,7 +385,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
393385 var templ_7745c5c3_Var17 string
394386 templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
395387 if templ_7745c5c3_Err != nil {
396- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 86, Col: 29}
388+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 84, Col: 29}
397389 }
398390 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
399391 if templ_7745c5c3_Err != nil {
@@ -416,7 +408,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
416408 var templ_7745c5c3_Var18 string
417409 templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
418410 if templ_7745c5c3_Err != nil {
419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 91, Col: 22}
411+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 89, Col: 22}
420412 }
421413 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18)
422414 if templ_7745c5c3_Err != nil {
@@ -434,7 +426,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
434426 var templ_7745c5c3_Var19 string
435427 templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
436428 if templ_7745c5c3_Err != nil {
437- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 93, Col: 22}
429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 91, Col: 22}
438430 }
439431 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)
440432 if templ_7745c5c3_Err != nil {
@@ -469,7 +461,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
469461 var templ_7745c5c3_Var20 string
470462 templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
471463 if templ_7745c5c3_Err != nil {
472- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 103, Col: 41}
464+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 101, Col: 41}
473465 }
474466 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
475467 if templ_7745c5c3_Err != nil {
@@ -509,6 +501,87 @@ func Commit(l Layout, p CommitPage) templ.Component {
509501 })
510502 }
511503
504+// diffViewMenu is the layout of the diff (unified, the default, or split) and
505+// the fold of its files, in one menu: a <details> that works without scripts;
506+// u, d and x still act without opening it. Its button names the layout shown.
507+func diffViewMenu(p DiffView) templ.Component {
508+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
509+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
510+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
511+ return templ_7745c5c3_CtxErr
512+ }
513+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
514+ if !templ_7745c5c3_IsBuffer {
515+ defer func() {
516+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
517+ if templ_7745c5c3_Err == nil {
518+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
519+ }
520+ }()
521+ }
522+ ctx = templ.InitializeContext(ctx)
523+ templ_7745c5c3_Var21 := templ.GetChildren(ctx)
524+ if templ_7745c5c3_Var21 == nil {
525+ templ_7745c5c3_Var21 = templ.NopComponent
526+ }
527+ ctx = templ.ClearChildren(ctx)
528+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<details class=\"menu vmenu\"><summary class=\"btn\" aria-label=\"Diff view\">")
529+ if templ_7745c5c3_Err != nil {
530+ return templ_7745c5c3_Err
531+ }
532+ if p.Both {
533+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<span hx-live=\"this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'\">")
534+ if templ_7745c5c3_Err != nil {
535+ return templ_7745c5c3_Err
536+ }
537+ var templ_7745c5c3_Var22 string
538+ templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(viewLabel(p.View))
539+ if templ_7745c5c3_Err != nil {
540+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 120, Col: 122}
541+ }
542+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
543+ if templ_7745c5c3_Err != nil {
544+ return templ_7745c5c3_Err
545+ }
546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "</span>")
547+ if templ_7745c5c3_Err != nil {
548+ return templ_7745c5c3_Err
549+ }
550+ } else {
551+ var templ_7745c5c3_Var23 string
552+ templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(viewLabel(p.View))
553+ if templ_7745c5c3_Err != nil {
554+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 122, Col: 23}
555+ }
556+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
557+ if templ_7745c5c3_Err != nil {
558+ return templ_7745c5c3_Err
559+ }
560+ }
561+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Diff view\">")
562+ if templ_7745c5c3_Err != nil {
563+ return templ_7745c5c3_Err
564+ }
565+ templ_7745c5c3_Err = viewLink(p, "unified", "Unified", "u", p.UnifiedHref).Render(ctx, templ_7745c5c3_Buffer)
566+ if templ_7745c5c3_Err != nil {
567+ return templ_7745c5c3_Err
568+ }
569+ templ_7745c5c3_Err = viewLink(p, "split", "Split", "d", p.SplitHref).Render(ctx, templ_7745c5c3_Buffer)
570+ if templ_7745c5c3_Err != nil {
571+ return templ_7745c5c3_Err
572+ }
573+ templ_7745c5c3_Err = collapseButton().Render(ctx, templ_7745c5c3_Buffer)
574+ if templ_7745c5c3_Err != nil {
575+ return templ_7745c5c3_Err
576+ }
577+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</div></details>")
578+ if templ_7745c5c3_Err != nil {
579+ return templ_7745c5c3_Err
580+ }
581+ return nil
582+ })
583+}
584+
512585 // viewLink is a button of the diff tools. It is a link, so that the split
513586 // layout works without JavaScript; with it, and when both layouts are in the
514587 // page, a click only flips the layout.
@@ -528,106 +601,106 @@ func viewLink(p DiffView, view, label, key, href string) templ.Component {
528601 }()
529602 }
530603 ctx = templ.InitializeContext(ctx)
531- templ_7745c5c3_Var21 := templ.GetChildren(ctx)
532- if templ_7745c5c3_Var21 == nil {
533- templ_7745c5c3_Var21 = templ.NopComponent
604+ templ_7745c5c3_Var24 := templ.GetChildren(ctx)
605+ if templ_7745c5c3_Var24 == nil {
606+ templ_7745c5c3_Var24 = templ.NopComponent
534607 }
535608 ctx = templ.ClearChildren(ctx)
536- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<a href=\"")
609+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "<a href=\"")
537610 if templ_7745c5c3_Err != nil {
538611 return templ_7745c5c3_Err
539612 }
540- var templ_7745c5c3_Var22 templ.SafeURL
541- templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
613+ var templ_7745c5c3_Var25 templ.SafeURL
614+ templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
542615 if templ_7745c5c3_Err != nil {
543- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 120, Col: 28}
616+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 138, Col: 28}
544617 }
545- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
618+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
546619 if templ_7745c5c3_Err != nil {
547620 return templ_7745c5c3_Err
548621 }
549- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\" class=\"btn vbtn\" data-view=\"")
622+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\" class=\"btn vbtn\" data-view=\"")
550623 if templ_7745c5c3_Err != nil {
551624 return templ_7745c5c3_Err
552625 }
553- var templ_7745c5c3_Var23 string
554- templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
626+ var templ_7745c5c3_Var26 string
627+ templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
555628 if templ_7745c5c3_Err != nil {
556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 122, Col: 18}
629+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 140, Col: 18}
557630 }
558- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
631+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var26)
559632 if templ_7745c5c3_Err != nil {
560633 return templ_7745c5c3_Err
561634 }
562- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" aria-keyshortcuts=\"")
635+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "\" aria-keyshortcuts=\"")
563636 if templ_7745c5c3_Err != nil {
564637 return templ_7745c5c3_Err
565638 }
566- var templ_7745c5c3_Var24 string
567- templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(key)
639+ var templ_7745c5c3_Var27 string
640+ templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.ResolveAttributeValue(key)
568641 if templ_7745c5c3_Err != nil {
569- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 123, Col: 25}
642+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 141, Col: 25}
570643 }
571- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24)
644+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var27)
572645 if templ_7745c5c3_Err != nil {
573646 return templ_7745c5c3_Err
574647 }
575- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\"")
648+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\"")
576649 if templ_7745c5c3_Err != nil {
577650 return templ_7745c5c3_Err
578651 }
579652 if p.View == view {
580- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, " aria-current=\"true\"")
653+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, " aria-current=\"true\"")
581654 if templ_7745c5c3_Err != nil {
582655 return templ_7745c5c3_Err
583656 }
584657 }
585658 if p.Both {
586- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " data-fire=\"")
659+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, " data-fire=\"")
587660 if templ_7745c5c3_Err != nil {
588661 return templ_7745c5c3_Err
589662 }
590- var templ_7745c5c3_Var25 string
591- templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
663+ var templ_7745c5c3_Var28 string
664+ templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
592665 if templ_7745c5c3_Err != nil {
593- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 128, Col: 19}
666+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 146, Col: 19}
594667 }
595- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var25)
668+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)
596669 if templ_7745c5c3_Err != nil {
597670 return templ_7745c5c3_Err
598671 }
599- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\" :aria-current=\"q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false\"")
672+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "\" :aria-current=\"q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false\"")
600673 if templ_7745c5c3_Err != nil {
601674 return templ_7745c5c3_Err
602675 }
603676 }
604- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, ">")
677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">")
605678 if templ_7745c5c3_Err != nil {
606679 return templ_7745c5c3_Err
607680 }
608- var templ_7745c5c3_Var26 string
609- templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(label)
681+ var templ_7745c5c3_Var29 string
682+ templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(label)
610683 if templ_7745c5c3_Err != nil {
611- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 131, Col: 9}
684+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 149, Col: 9}
612685 }
613- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
686+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
614687 if templ_7745c5c3_Err != nil {
615688 return templ_7745c5c3_Err
616689 }
617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<kbd aria-hidden=\"true\">")
690+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "<kbd aria-hidden=\"true\">")
618691 if templ_7745c5c3_Err != nil {
619692 return templ_7745c5c3_Err
620693 }
621- var templ_7745c5c3_Var27 string
622- templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(key)
694+ var templ_7745c5c3_Var30 string
695+ templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(key)
623696 if templ_7745c5c3_Err != nil {
624- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 131, Col: 40}
697+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 149, Col: 40}
625698 }
626- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
699+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
627700 if templ_7745c5c3_Err != nil {
628701 return templ_7745c5c3_Err
629702 }
630- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "</kbd></a>")
703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "</kbd></a>")
631704 if templ_7745c5c3_Err != nil {
632705 return templ_7745c5c3_Err
633706 }
@@ -653,12 +726,12 @@ func collapseButton() templ.Component {
653726 }()
654727 }
655728 ctx = templ.InitializeContext(ctx)
656- templ_7745c5c3_Var28 := templ.GetChildren(ctx)
657- if templ_7745c5c3_Var28 == nil {
658- templ_7745c5c3_Var28 = templ.NopComponent
729+ templ_7745c5c3_Var31 := templ.GetChildren(ctx)
730+ if templ_7745c5c3_Var31 == nil {
731+ templ_7745c5c3_Var31 = templ.NopComponent
659732 }
660733 ctx = templ.ClearChildren(ctx)
661- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "<button type=\"button\" aria-keyshortcuts=\"x\" data-js data-fire=\"collapse\" class=\"btn\"><span hx-live=\"this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'\">Collapse all</span><kbd aria-hidden=\"true\">x</kbd></button>")
734+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<button type=\"button\" aria-keyshortcuts=\"x\" data-js data-fire=\"collapse\" class=\"btn\"><span hx-live=\"this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'\">Collapse all</span><kbd aria-hidden=\"true\">x</kbd></button>")
662735 if templ_7745c5c3_Err != nil {
663736 return templ_7745c5c3_Err
664737 }
@@ -682,83 +755,83 @@ func personView(pr Person) templ.Component {
682755 }()
683756 }
684757 ctx = templ.InitializeContext(ctx)
685- templ_7745c5c3_Var29 := templ.GetChildren(ctx)
686- if templ_7745c5c3_Var29 == nil {
687- templ_7745c5c3_Var29 = templ.NopComponent
758+ templ_7745c5c3_Var32 := templ.GetChildren(ctx)
759+ if templ_7745c5c3_Var32 == nil {
760+ templ_7745c5c3_Var32 = templ.NopComponent
688761 }
689762 ctx = templ.ClearChildren(ctx)
690- var templ_7745c5c3_Var30 string
691- templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(pr.Name)
763+ var templ_7745c5c3_Var33 string
764+ templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(pr.Name)
692765 if templ_7745c5c3_Err != nil {
693- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 143, Col: 10}
766+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 161, Col: 10}
694767 }
695- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
768+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
696769 if templ_7745c5c3_Err != nil {
697770 return templ_7745c5c3_Err
698771 }
699- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " ")
772+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, " ")
700773 if templ_7745c5c3_Err != nil {
701774 return templ_7745c5c3_Err
702775 }
703776 if pr.WhenAt != "" {
704- var templ_7745c5c3_Var31 string
705- templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
777+ var templ_7745c5c3_Var34 string
778+ templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
706779 if templ_7745c5c3_Err != nil {
707- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 10}
780+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 10}
708781 }
709- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
782+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
710783 if templ_7745c5c3_Err != nil {
711784 return templ_7745c5c3_Err
712785 }
713- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "<time datetime=\"")
786+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "<time datetime=\"")
714787 if templ_7745c5c3_Err != nil {
715788 return templ_7745c5c3_Err
716789 }
717- var templ_7745c5c3_Var32 string
718- templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.WhenAt)
790+ var templ_7745c5c3_Var35 string
791+ templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.WhenAt)
719792 if templ_7745c5c3_Err != nil {
720- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 38}
793+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 38}
721794 }
722- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var32)
795+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var35)
723796 if templ_7745c5c3_Err != nil {
724797 return templ_7745c5c3_Err
725798 }
726- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "\" title=\"")
799+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "\" title=\"")
727800 if templ_7745c5c3_Err != nil {
728801 return templ_7745c5c3_Err
729802 }
730- var templ_7745c5c3_Var33 string
731- templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.Abs)
803+ var templ_7745c5c3_Var36 string
804+ templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.Abs)
732805 if templ_7745c5c3_Err != nil {
733- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 55}
806+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 55}
734807 }
735- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var33)
808+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var36)
736809 if templ_7745c5c3_Err != nil {
737810 return templ_7745c5c3_Err
738811 }
739- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "\">")
812+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "\">")
740813 if templ_7745c5c3_Err != nil {
741814 return templ_7745c5c3_Err
742815 }
743- var templ_7745c5c3_Var34 string
744- templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(pr.When)
816+ var templ_7745c5c3_Var37 string
817+ templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(pr.When)
745818 if templ_7745c5c3_Err != nil {
746- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 67}
819+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 67}
747820 }
748- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
821+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
749822 if templ_7745c5c3_Err != nil {
750823 return templ_7745c5c3_Err
751824 }
752- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "</time>")
825+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "</time>")
753826 if templ_7745c5c3_Err != nil {
754827 return templ_7745c5c3_Err
755828 }
756- var templ_7745c5c3_Var35 string
757- templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + pr.Abs)
829+ var templ_7745c5c3_Var38 string
830+ templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + pr.Abs)
758831 if templ_7745c5c3_Err != nil {
759- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 93}
832+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 93}
760833 }
761- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
834+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
762835 if templ_7745c5c3_Err != nil {
763836 return templ_7745c5c3_Err
764837 }
@@ -783,25 +856,25 @@ func commitRail(p CommitPage) templ.Component {
783856 }()
784857 }
785858 ctx = templ.InitializeContext(ctx)
786- templ_7745c5c3_Var36 := templ.GetChildren(ctx)
787- if templ_7745c5c3_Var36 == nil {
788- templ_7745c5c3_Var36 = templ.NopComponent
859+ templ_7745c5c3_Var39 := templ.GetChildren(ctx)
860+ if templ_7745c5c3_Var39 == nil {
861+ templ_7745c5c3_Var39 = templ.NopComponent
789862 }
790863 ctx = templ.ClearChildren(ctx)
791- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
864+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
792865 if templ_7745c5c3_Err != nil {
793866 return templ_7745c5c3_Err
794867 }
795- var templ_7745c5c3_Var37 string
796- templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
868+ var templ_7745c5c3_Var40 string
869+ templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
797870 if templ_7745c5c3_Err != nil {
798- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 151, Col: 65}
871+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 169, Col: 65}
799872 }
800- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
873+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40))
801874 if templ_7745c5c3_Err != nil {
802875 return templ_7745c5c3_Err
803876 }
804- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "</span></h2>")
877+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</span></h2>")
805878 if templ_7745c5c3_Err != nil {
806879 return templ_7745c5c3_Err
807880 }
@@ -809,7 +882,7 @@ func commitRail(p CommitPage) templ.Component {
809882 if templ_7745c5c3_Err != nil {
810883 return templ_7745c5c3_Err
811884 }
812- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "</section>")
885+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</section>")
813886 if templ_7745c5c3_Err != nil {
814887 return templ_7745c5c3_Err
815888 }
@@ -835,236 +908,236 @@ func FileList(files []DiffFile) templ.Component {
835908 }()
836909 }
837910 ctx = templ.InitializeContext(ctx)
838- templ_7745c5c3_Var38 := templ.GetChildren(ctx)
839- if templ_7745c5c3_Var38 == nil {
840- templ_7745c5c3_Var38 = templ.NopComponent
911+ templ_7745c5c3_Var41 := templ.GetChildren(ctx)
912+ if templ_7745c5c3_Var41 == nil {
913+ templ_7745c5c3_Var41 = templ.NopComponent
841914 }
842915 ctx = templ.ClearChildren(ctx)
843916 if len(files) > fileFilterMin {
844- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<div class=\"ffilter\"><label for=\"files-filter\" class=\"sr\">filter the changed files</label> <input id=\"files-filter\" type=\"search\" placeholder=\"Filter files…\" autocomplete=\"off\" data-pick=\".files > li\" hx-on:input=\"ermite.filter(this)\"></div>")
917+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "<div class=\"ffilter\"><label for=\"files-filter\" class=\"sr\">filter the changed files</label> <input id=\"files-filter\" type=\"search\" placeholder=\"Filter files…\" autocomplete=\"off\" data-pick=\".files > li\" hx-on:input=\"ermite.filter(this)\"></div>")
845918 if templ_7745c5c3_Err != nil {
846919 return templ_7745c5c3_Err
847920 }
848921 }
849- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<ol class=\"files\" aria-label=\"Changed files\">")
922+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<ol class=\"files\" aria-label=\"Changed files\">")
850923 if templ_7745c5c3_Err != nil {
851924 return templ_7745c5c3_Err
852925 }
853926 for _, f := range files {
854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "<li><a href=\"")
927+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "<li><a href=\"")
855928 if templ_7745c5c3_Err != nil {
856929 return templ_7745c5c3_Err
857930 }
858- var templ_7745c5c3_Var39 templ.SafeURL
859- templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("#" + f.ID))
931+ var templ_7745c5c3_Var42 templ.SafeURL
932+ templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("#" + f.ID))
860933 if templ_7745c5c3_Err != nil {
861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 176, Col: 37}
934+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 194, Col: 37}
862935 }
863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
936+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
864937 if templ_7745c5c3_Err != nil {
865938 return templ_7745c5c3_Err
866939 }
867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "\" title=\"")
940+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\" title=\"")
868941 if templ_7745c5c3_Err != nil {
869942 return templ_7745c5c3_Err
870943 }
871- var templ_7745c5c3_Var40 string
872- templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
944+ var templ_7745c5c3_Var43 string
945+ templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
873946 if templ_7745c5c3_Err != nil {
874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 177, Col: 19}
947+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 195, Col: 19}
875948 }
876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)
949+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var43)
877950 if templ_7745c5c3_Err != nil {
878951 return templ_7745c5c3_Err
879952 }
880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "\" hx-on:click=\"(window.ermiteMR?.openFile || ermite.openFile)(this.hash.slice(1))\"><span class=\"st\" data-st=\"")
953+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\" hx-on:click=\"(window.ermiteMR?.openFile || ermite.openFile)(this.hash.slice(1))\"><span class=\"st\" data-st=\"")
881954 if templ_7745c5c3_Err != nil {
882955 return templ_7745c5c3_Err
883956 }
884- var templ_7745c5c3_Var41 string
885- templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Status)
957+ var templ_7745c5c3_Var44 string
958+ templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Status)
886959 if templ_7745c5c3_Err != nil {
887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 40}
960+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 40}
888961 }
889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var41)
962+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var44)
890963 if templ_7745c5c3_Err != nil {
891964 return templ_7745c5c3_Err
892965 }
893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "\" title=\"")
966+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" title=\"")
894967 if templ_7745c5c3_Err != nil {
895968 return templ_7745c5c3_Err
896969 }
897- var templ_7745c5c3_Var42 string
898- templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.ResolveAttributeValue(statusName(f.Status))
970+ var templ_7745c5c3_Var45 string
971+ templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.ResolveAttributeValue(statusName(f.Status))
899972 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 71}
973+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 71}
901974 }
902- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var42)
975+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var45)
903976 if templ_7745c5c3_Err != nil {
904977 return templ_7745c5c3_Err
905978 }
906- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "\">")
979+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "\">")
907980 if templ_7745c5c3_Err != nil {
908981 return templ_7745c5c3_Err
909982 }
910- var templ_7745c5c3_Var43 string
911- templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
983+ var templ_7745c5c3_Var46 string
984+ templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
912985 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 84}
986+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 84}
914987 }
915- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
988+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916989 if templ_7745c5c3_Err != nil {
917990 return templ_7745c5c3_Err
918991 }
919- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</span> <span class=\"nm\"><span class=\"p\">")
992+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "</span> <span class=\"nm\"><span class=\"p\">")
920993 if templ_7745c5c3_Err != nil {
921994 return templ_7745c5c3_Err
922995 }
923- var templ_7745c5c3_Var44 string
924- templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(f.Name)
996+ var templ_7745c5c3_Var47 string
997+ templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(f.Name)
925998 if templ_7745c5c3_Err != nil {
926- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 46}
999+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 46}
9271000 }
928- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
1001+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
9291002 if templ_7745c5c3_Err != nil {
9301003 return templ_7745c5c3_Err
9311004 }
932- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "</span>")
1005+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</span>")
9331006 if templ_7745c5c3_Err != nil {
9341007 return templ_7745c5c3_Err
9351008 }
936- var templ_7745c5c3_Var45 string
937- templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1009+ var templ_7745c5c3_Var48 string
1010+ templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
9381011 if templ_7745c5c3_Err != nil {
939- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 60}
1012+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 60}
9401013 }
941- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
1014+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
9421015 if templ_7745c5c3_Err != nil {
9431016 return templ_7745c5c3_Err
9441017 }
945- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<span class=\"d\"><bdi>")
1018+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<span class=\"d\"><bdi>")
9461019 if templ_7745c5c3_Err != nil {
9471020 return templ_7745c5c3_Err
9481021 }
949- var templ_7745c5c3_Var46 string
950- templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(f.Dir)
1022+ var templ_7745c5c3_Var49 string
1023+ templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(f.Dir)
9511024 if templ_7745c5c3_Err != nil {
952- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 90}
1025+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 90}
9531026 }
954- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
1027+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
9551028 if templ_7745c5c3_Err != nil {
9561029 return templ_7745c5c3_Err
9571030 }
958- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</bdi></span></span> ")
1031+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</bdi></span></span> ")
9591032 if templ_7745c5c3_Err != nil {
9601033 return templ_7745c5c3_Err
9611034 }
9621035 if f.OpenNotes > 0 {
963- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<span class=\"cn\" title=\"")
1036+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<span class=\"cn\" title=\"")
9641037 if templ_7745c5c3_Err != nil {
9651038 return templ_7745c5c3_Err
9661039 }
967- var templ_7745c5c3_Var47 string
968- templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.OpenNotes, "open comment", "open comments"))
1040+ var templ_7745c5c3_Var50 string
1041+ templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.OpenNotes, "open comment", "open comments"))
9691042 if templ_7745c5c3_Err != nil {
970- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 183, Col: 83}
1043+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 201, Col: 83}
9711044 }
972- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var47)
1045+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)
9731046 if templ_7745c5c3_Err != nil {
9741047 return templ_7745c5c3_Err
9751048 }
976- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\">")
1049+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "\">")
9771050 if templ_7745c5c3_Err != nil {
9781051 return templ_7745c5c3_Err
9791052 }
980- var templ_7745c5c3_Var48 string
981- templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.OpenNotes))
1053+ var templ_7745c5c3_Var51 string
1054+ templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.OpenNotes))
9821055 if templ_7745c5c3_Err != nil {
983- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 183, Col: 105}
1056+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 201, Col: 105}
9841057 }
985- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
1058+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
9861059 if templ_7745c5c3_Err != nil {
9871060 return templ_7745c5c3_Err
9881061 }
989- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</span> ")
1062+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</span> ")
9901063 if templ_7745c5c3_Err != nil {
9911064 return templ_7745c5c3_Err
9921065 }
9931066 } else if f.Notes > 0 {
994- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<span class=\"cn done\" title=\"")
1067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "<span class=\"cn done\" title=\"")
9951068 if templ_7745c5c3_Err != nil {
9961069 return templ_7745c5c3_Err
9971070 }
998- var templ_7745c5c3_Var49 string
999- templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.Notes, "resolved comment", "resolved comments"))
1071+ var templ_7745c5c3_Var52 string
1072+ templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.Notes, "resolved comment", "resolved comments"))
10001073 if templ_7745c5c3_Err != nil {
1001- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 185, Col: 92}
1074+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 203, Col: 92}
10021075 }
1003- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)
1076+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
10041077 if templ_7745c5c3_Err != nil {
10051078 return templ_7745c5c3_Err
10061079 }
1007- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "\">")
1080+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "\">")
10081081 if templ_7745c5c3_Err != nil {
10091082 return templ_7745c5c3_Err
10101083 }
1011- var templ_7745c5c3_Var50 string
1012- templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Notes))
1084+ var templ_7745c5c3_Var53 string
1085+ templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Notes))
10131086 if templ_7745c5c3_Err != nil {
1014- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 185, Col: 110}
1087+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 203, Col: 110}
10151088 }
1016- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
1089+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53))
10171090 if templ_7745c5c3_Err != nil {
10181091 return templ_7745c5c3_Err
10191092 }
1020- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "</span> ")
1093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</span> ")
10211094 if templ_7745c5c3_Err != nil {
10221095 return templ_7745c5c3_Err
10231096 }
10241097 }
10251098 if f.Bin {
1026- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<span class=\"n mute\">bin</span>")
1099+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<span class=\"n mute\">bin</span>")
10271100 if templ_7745c5c3_Err != nil {
10281101 return templ_7745c5c3_Err
10291102 }
10301103 } else {
1031- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "<span class=\"n\"><span class=\"plus\">+")
1104+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<span class=\"n\"><span class=\"plus\">+")
10321105 if templ_7745c5c3_Err != nil {
10331106 return templ_7745c5c3_Err
10341107 }
1035- var templ_7745c5c3_Var51 string
1036- templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
1108+ var templ_7745c5c3_Var54 string
1109+ templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
10371110 if templ_7745c5c3_Err != nil {
1038- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 190, Col: 55}
1111+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 208, Col: 55}
10391112 }
1040- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
1113+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
10411114 if templ_7745c5c3_Err != nil {
10421115 return templ_7745c5c3_Err
10431116 }
1044- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "</span> <span class=\"minus\">-")
1117+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "</span> <span class=\"minus\">-")
10451118 if templ_7745c5c3_Err != nil {
10461119 return templ_7745c5c3_Err
10471120 }
1048- var templ_7745c5c3_Var52 string
1049- templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
1121+ var templ_7745c5c3_Var55 string
1122+ templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
10501123 if templ_7745c5c3_Err != nil {
1051- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 190, Col: 99}
1124+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 208, Col: 99}
10521125 }
1053- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))
1126+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
10541127 if templ_7745c5c3_Err != nil {
10551128 return templ_7745c5c3_Err
10561129 }
1057- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "</span></span>")
1130+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "</span></span>")
10581131 if templ_7745c5c3_Err != nil {
10591132 return templ_7745c5c3_Err
10601133 }
10611134 }
1062- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</a></li>")
1135+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "</a></li>")
10631136 if templ_7745c5c3_Err != nil {
10641137 return templ_7745c5c3_Err
10651138 }
10661139 }
1067- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "</ol>")
1140+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "</ol>")
10681141 if templ_7745c5c3_Err != nil {
10691142 return templ_7745c5c3_Err
10701143 }
@@ -1092,270 +1165,283 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
10921165 }()
10931166 }
10941167 ctx = templ.InitializeContext(ctx)
1095- templ_7745c5c3_Var53 := templ.GetChildren(ctx)
1096- if templ_7745c5c3_Var53 == nil {
1097- templ_7745c5c3_Var53 = templ.NopComponent
1168+ templ_7745c5c3_Var56 := templ.GetChildren(ctx)
1169+ if templ_7745c5c3_Var56 == nil {
1170+ templ_7745c5c3_Var56 = templ.NopComponent
10981171 }
10991172 ctx = templ.ClearChildren(ctx)
1100- var templ_7745c5c3_Var54 = []any{"dfile", "lnw-" + itoa(f.Digits)}
1101- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var54...)
1173+ var templ_7745c5c3_Var57 = []any{"dfile", "lnw-" + itoa(f.Digits)}
1174+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var57...)
11021175 if templ_7745c5c3_Err != nil {
11031176 return templ_7745c5c3_Err
11041177 }
1105- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<details class=\"")
1178+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "<details class=\"")
11061179 if templ_7745c5c3_Err != nil {
11071180 return templ_7745c5c3_Err
11081181 }
1109- var templ_7745c5c3_Var55 string
1110- templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var54).String())
1182+ var templ_7745c5c3_Var58 string
1183+ templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var57).String())
11111184 if templ_7745c5c3_Err != nil {
11121185 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
11131186 }
1114- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var55)
1187+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var58)
11151188 if templ_7745c5c3_Err != nil {
11161189 return templ_7745c5c3_Err
11171190 }
1118- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "\" id=\"")
1191+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "\" id=\"")
11191192 if templ_7745c5c3_Err != nil {
11201193 return templ_7745c5c3_Err
11211194 }
1122- var templ_7745c5c3_Var56 string
1123- templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID)
1195+ var templ_7745c5c3_Var59 string
1196+ templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID)
11241197 if templ_7745c5c3_Err != nil {
1125- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 205, Col: 11}
1198+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 223, Col: 11}
11261199 }
1127- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var56)
1200+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var59)
11281201 if templ_7745c5c3_Err != nil {
11291202 return templ_7745c5c3_Err
11301203 }
1131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "\" data-file")
1204+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\" data-file=\"")
1205+ if templ_7745c5c3_Err != nil {
1206+ return templ_7745c5c3_Err
1207+ }
1208+ var templ_7745c5c3_Var60 string
1209+ templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Key)
1210+ if templ_7745c5c3_Err != nil {
1211+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 224, Col: 19}
1212+ }
1213+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var60)
1214+ if templ_7745c5c3_Err != nil {
1215+ return templ_7745c5c3_Err
1216+ }
1217+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "\"")
11321218 if templ_7745c5c3_Err != nil {
11331219 return templ_7745c5c3_Err
11341220 }
11351221 if f.Open {
1136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, " open")
1222+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, " open")
11371223 if templ_7745c5c3_Err != nil {
11381224 return templ_7745c5c3_Err
11391225 }
11401226 }
1141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "><summary><span class=\"st\">")
1227+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "><summary><span class=\"st\">")
11421228 if templ_7745c5c3_Err != nil {
11431229 return templ_7745c5c3_Err
11441230 }
1145- var templ_7745c5c3_Var57 string
1146- templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
1231+ var templ_7745c5c3_Var61 string
1232+ templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
11471233 if templ_7745c5c3_Err != nil {
1148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 30}
1234+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 30}
11491235 }
1150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))
1236+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))
11511237 if templ_7745c5c3_Err != nil {
11521238 return templ_7745c5c3_Err
11531239 }
1154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "</span>")
1240+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "</span>")
11551241 if templ_7745c5c3_Err != nil {
11561242 return templ_7745c5c3_Err
11571243 }
1158- var templ_7745c5c3_Var58 string
1159- templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1244+ var templ_7745c5c3_Var62 string
1245+ templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
11601246 if templ_7745c5c3_Err != nil {
1161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 44}
1247+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 44}
11621248 }
1163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))
1249+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
11641250 if templ_7745c5c3_Err != nil {
11651251 return templ_7745c5c3_Err
11661252 }
1167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "<span class=\"p\">")
1253+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<span class=\"p\">")
11681254 if templ_7745c5c3_Err != nil {
11691255 return templ_7745c5c3_Err
11701256 }
1171- var templ_7745c5c3_Var59 string
1172- templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(f.Path)
1257+ var templ_7745c5c3_Var63 string
1258+ templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(f.Path)
11731259 if templ_7745c5c3_Err != nil {
1174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 70}
1260+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 70}
11751261 }
1176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))
1262+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63))
11771263 if templ_7745c5c3_Err != nil {
11781264 return templ_7745c5c3_Err
11791265 }
1180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "</span>")
1266+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "</span>")
11811267 if templ_7745c5c3_Err != nil {
11821268 return templ_7745c5c3_Err
11831269 }
1184- var templ_7745c5c3_Var60 string
1185- templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1270+ var templ_7745c5c3_Var64 string
1271+ templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
11861272 if templ_7745c5c3_Err != nil {
1187- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 84}
1273+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 84}
11881274 }
1189- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var60))
1275+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
11901276 if templ_7745c5c3_Err != nil {
11911277 return templ_7745c5c3_Err
11921278 }
1193- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "<span class=\"plus\">+")
1279+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "<span class=\"plus\">+")
11941280 if templ_7745c5c3_Err != nil {
11951281 return templ_7745c5c3_Err
11961282 }
1197- var templ_7745c5c3_Var61 string
1198- templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
1283+ var templ_7745c5c3_Var65 string
1284+ templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
11991285 if templ_7745c5c3_Err != nil {
1200- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 119}
1286+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 119}
12011287 }
1202- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))
1288+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
12031289 if templ_7745c5c3_Err != nil {
12041290 return templ_7745c5c3_Err
12051291 }
1206- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</span>")
1292+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "</span>")
12071293 if templ_7745c5c3_Err != nil {
12081294 return templ_7745c5c3_Err
12091295 }
1210- var templ_7745c5c3_Var62 string
1211- templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1296+ var templ_7745c5c3_Var66 string
1297+ templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
12121298 if templ_7745c5c3_Err != nil {
1213- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 133}
1299+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 133}
12141300 }
1215- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
1301+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))
12161302 if templ_7745c5c3_Err != nil {
12171303 return templ_7745c5c3_Err
12181304 }
1219- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "<span class=\"minus\">-")
1305+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<span class=\"minus\">-")
12201306 if templ_7745c5c3_Err != nil {
12211307 return templ_7745c5c3_Err
12221308 }
1223- var templ_7745c5c3_Var63 string
1224- templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
1309+ var templ_7745c5c3_Var67 string
1310+ templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
12251311 if templ_7745c5c3_Err != nil {
1226- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 169}
1312+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 169}
12271313 }
1228- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63))
1314+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))
12291315 if templ_7745c5c3_Err != nil {
12301316 return templ_7745c5c3_Err
12311317 }
1232- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "</span> ")
1318+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "</span> ")
12331319 if templ_7745c5c3_Err != nil {
12341320 return templ_7745c5c3_Err
12351321 }
12361322 if f.Note != "" {
1237- var templ_7745c5c3_Var64 string
1238- templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1323+ var templ_7745c5c3_Var68 string
1324+ templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
12391325 if templ_7745c5c3_Err != nil {
1240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 214, Col: 9}
1326+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 232, Col: 9}
12411327 }
1242- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
1328+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
12431329 if templ_7745c5c3_Err != nil {
12441330 return templ_7745c5c3_Err
12451331 }
1246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<span class=\"note\">")
1332+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "<span class=\"note\">")
12471333 if templ_7745c5c3_Err != nil {
12481334 return templ_7745c5c3_Err
12491335 }
1250- var templ_7745c5c3_Var65 string
1251- templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
1336+ var templ_7745c5c3_Var69 string
1337+ templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
12521338 if templ_7745c5c3_Err != nil {
1253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 214, Col: 38}
1339+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 232, Col: 38}
12541340 }
1255- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
1341+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
12561342 if templ_7745c5c3_Err != nil {
12571343 return templ_7745c5c3_Err
12581344 }
1259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "</span>")
1345+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "</span>")
12601346 if templ_7745c5c3_Err != nil {
12611347 return templ_7745c5c3_Err
12621348 }
12631349 }
1264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "</summary> ")
1350+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "</summary> ")
12651351 if templ_7745c5c3_Err != nil {
12661352 return templ_7745c5c3_Err
12671353 }
12681354 if f.Lazy {
1269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, " ")
1355+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, " ")
12701356 if templ_7745c5c3_Err != nil {
12711357 return templ_7745c5c3_Err
12721358 }
1273- var templ_7745c5c3_Var66 = []any{"dlazy", "dlazy-" + itoa(f.Height)}
1274- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var66...)
1359+ var templ_7745c5c3_Var70 = []any{"dlazy", "dlazy-" + itoa(f.Height)}
1360+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var70...)
12751361 if templ_7745c5c3_Err != nil {
12761362 return templ_7745c5c3_Err
12771363 }
1278- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<div class=\"")
1364+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "<div class=\"")
12791365 if templ_7745c5c3_Err != nil {
12801366 return templ_7745c5c3_Err
12811367 }
1282- var templ_7745c5c3_Var67 string
1283- templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var66).String())
1368+ var templ_7745c5c3_Var71 string
1369+ templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var70).String())
12841370 if templ_7745c5c3_Err != nil {
12851371 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
12861372 }
1287- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)
1373+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)
12881374 if templ_7745c5c3_Err != nil {
12891375 return templ_7745c5c3_Err
12901376 }
1291- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "\" data-src=\"")
1377+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, "\" data-src=\"")
12921378 if templ_7745c5c3_Err != nil {
12931379 return templ_7745c5c3_Err
12941380 }
1295- var templ_7745c5c3_Var68 string
1296- templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Src)
1381+ var templ_7745c5c3_Var72 string
1382+ templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Src)
12971383 if templ_7745c5c3_Err != nil {
1298- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 221, Col: 69}
1384+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 239, Col: 69}
12991385 }
1300- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var68)
1386+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72)
13011387 if templ_7745c5c3_Err != nil {
13021388 return templ_7745c5c3_Err
13031389 }
1304- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "\" data-notes=\"")
1390+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "\" data-notes=\"")
13051391 if templ_7745c5c3_Err != nil {
13061392 return templ_7745c5c3_Err
13071393 }
1308- var templ_7745c5c3_Var69 string
1309- templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Comments)
1394+ var templ_7745c5c3_Var73 string
1395+ templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Comments)
13101396 if templ_7745c5c3_Err != nil {
1311- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 221, Col: 95}
1397+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 239, Col: 95}
13121398 }
1313- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69)
1399+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var73)
13141400 if templ_7745c5c3_Err != nil {
13151401 return templ_7745c5c3_Err
13161402 }
1317- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "\"><a href=\"")
1403+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "\"><a href=\"")
13181404 if templ_7745c5c3_Err != nil {
13191405 return templ_7745c5c3_Err
13201406 }
1321- var templ_7745c5c3_Var70 templ.SafeURL
1322- templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?from=" + itoa(f.From) + "#" + f.ID))
1407+ var templ_7745c5c3_Var74 templ.SafeURL
1408+ templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?from=" + itoa(f.From) + "#" + f.ID))
13231409 if templ_7745c5c3_Err != nil {
1324- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 222, Col: 65}
1410+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 240, Col: 65}
13251411 }
1326- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
1412+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
13271413 if templ_7745c5c3_Err != nil {
13281414 return templ_7745c5c3_Err
13291415 }
1330- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "\">show this file</a></div>")
1416+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "\">show this file</a></div>")
13311417 if templ_7745c5c3_Err != nil {
13321418 return templ_7745c5c3_Err
13331419 }
13341420 } else if len(f.Hunks) > 0 {
1335- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "<div class=\"dscroll\">")
1421+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "<div class=\"dscroll\">")
13361422 if templ_7745c5c3_Err != nil {
13371423 return templ_7745c5c3_Err
13381424 }
13391425 if p.ShowUnified {
1340- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "<table class=\"dt uni\" aria-label=\"")
1426+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 125, "<table class=\"dt uni\" aria-label=\"")
13411427 if templ_7745c5c3_Err != nil {
13421428 return templ_7745c5c3_Err
13431429 }
1344- var templ_7745c5c3_Var71 string
1345- templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", unified")
1430+ var templ_7745c5c3_Var75 string
1431+ templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", unified")
13461432 if templ_7745c5c3_Err != nil {
1347- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 227, Col: 60}
1433+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 245, Col: 60}
13481434 }
1349- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)
1435+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
13501436 if templ_7745c5c3_Err != nil {
13511437 return templ_7745c5c3_Err
13521438 }
1353- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, "\">")
1439+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 126, "\">")
13541440 if templ_7745c5c3_Err != nil {
13551441 return templ_7745c5c3_Err
13561442 }
13571443 for _, h := range f.Hunks {
1358- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "<tbody>")
1444+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, "<tbody>")
13591445 if templ_7745c5c3_Err != nil {
13601446 return templ_7745c5c3_Err
13611447 }
@@ -1365,43 +1451,43 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
13651451 return templ_7745c5c3_Err
13661452 }
13671453 }
1368- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "<tr class=\"hunk\"><td colspan=\"4\">")
1454+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "<tr class=\"hunk\"><td colspan=\"4\">")
13691455 if templ_7745c5c3_Err != nil {
13701456 return templ_7745c5c3_Err
13711457 }
1372- var templ_7745c5c3_Var72 string
1373- templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
1458+ var templ_7745c5c3_Var76 string
1459+ templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
13741460 if templ_7745c5c3_Err != nil {
1375- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 233, Col: 51}
1461+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 251, Col: 51}
13761462 }
1377- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))
1463+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
13781464 if templ_7745c5c3_Err != nil {
13791465 return templ_7745c5c3_Err
13801466 }
1381- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "</td></tr>")
1467+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "</td></tr>")
13821468 if templ_7745c5c3_Err != nil {
13831469 return templ_7745c5c3_Err
13841470 }
13851471 for _, ln := range h.Lines {
1386- var templ_7745c5c3_Var73 = []any{ln.Kind, templ.KV("sel", ln.Selected)}
1387- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var73...)
1472+ var templ_7745c5c3_Var77 = []any{ln.Kind, templ.KV("sel", ln.Selected)}
1473+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var77...)
13881474 if templ_7745c5c3_Err != nil {
13891475 return templ_7745c5c3_Err
13901476 }
1391- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "<tr class=\"")
1477+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "<tr class=\"")
13921478 if templ_7745c5c3_Err != nil {
13931479 return templ_7745c5c3_Err
13941480 }
1395- var templ_7745c5c3_Var74 string
1396- templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var73).String())
1481+ var templ_7745c5c3_Var78 string
1482+ templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var77).String())
13971483 if templ_7745c5c3_Err != nil {
13981484 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
13991485 }
1400- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var74)
1486+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var78)
14011487 if templ_7745c5c3_Err != nil {
14021488 return templ_7745c5c3_Err
14031489 }
1404- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 125, "\"><td class=\"ln\">")
1490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 131, "\"><td class=\"ln\">")
14051491 if templ_7745c5c3_Err != nil {
14061492 return templ_7745c5c3_Err
14071493 }
@@ -1409,7 +1495,7 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
14091495 if templ_7745c5c3_Err != nil {
14101496 return templ_7745c5c3_Err
14111497 }
1412- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 126, "</td><td class=\"ln\">")
1498+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 132, "</td><td class=\"ln\">")
14131499 if templ_7745c5c3_Err != nil {
14141500 return templ_7745c5c3_Err
14151501 }
@@ -1417,20 +1503,20 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
14171503 if templ_7745c5c3_Err != nil {
14181504 return templ_7745c5c3_Err
14191505 }
1420- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, "</td><td class=\"m\">")
1506+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 133, "</td><td class=\"m\">")
14211507 if templ_7745c5c3_Err != nil {
14221508 return templ_7745c5c3_Err
14231509 }
1424- var templ_7745c5c3_Var75 string
1425- templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
1510+ var templ_7745c5c3_Var79 string
1511+ templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
14261512 if templ_7745c5c3_Err != nil {
1427- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 238, Col: 33}
1513+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 256, Col: 33}
14281514 }
1429- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75))
1515+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
14301516 if templ_7745c5c3_Err != nil {
14311517 return templ_7745c5c3_Err
14321518 }
1433- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "</td><td class=\"tx chroma\">")
1519+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 134, "</td><td class=\"tx chroma\">")
14341520 if templ_7745c5c3_Err != nil {
14351521 return templ_7745c5c3_Err
14361522 }
@@ -1438,12 +1524,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
14381524 if templ_7745c5c3_Err != nil {
14391525 return templ_7745c5c3_Err
14401526 }
1441- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "</td></tr>")
1527+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 135, "</td></tr>")
14421528 if templ_7745c5c3_Err != nil {
14431529 return templ_7745c5c3_Err
14441530 }
14451531 if len(ln.Notes) > 0 || ln.Form != nil {
1446- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "<tr class=\"fnote\"><td colspan=\"3\"></td><td>")
1532+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 136, "<tr class=\"fnote\"><td colspan=\"3\"></td><td>")
14471533 if templ_7745c5c3_Err != nil {
14481534 return templ_7745c5c3_Err
14491535 }
@@ -1451,19 +1537,19 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
14511537 if templ_7745c5c3_Err != nil {
14521538 return templ_7745c5c3_Err
14531539 }
1454- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 131, "</td></tr>")
1540+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 137, "</td></tr>")
14551541 if templ_7745c5c3_Err != nil {
14561542 return templ_7745c5c3_Err
14571543 }
14581544 }
14591545 }
1460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 132, "</tbody> ")
1546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 138, "</tbody> ")
14611547 if templ_7745c5c3_Err != nil {
14621548 return templ_7745c5c3_Err
14631549 }
14641550 }
14651551 if f.Tail != nil {
1466- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 133, "<tbody>")
1552+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 139, "<tbody>")
14671553 if templ_7745c5c3_Err != nil {
14681554 return templ_7745c5c3_Err
14691555 }
@@ -1471,36 +1557,36 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
14711557 if templ_7745c5c3_Err != nil {
14721558 return templ_7745c5c3_Err
14731559 }
1474- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 134, "</tbody>")
1560+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 140, "</tbody>")
14751561 if templ_7745c5c3_Err != nil {
14761562 return templ_7745c5c3_Err
14771563 }
14781564 }
1479- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 135, "</table>")
1565+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 141, "</table>")
14801566 if templ_7745c5c3_Err != nil {
14811567 return templ_7745c5c3_Err
14821568 }
14831569 }
14841570 if p.ShowSplit {
1485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 136, "<table class=\"dt spl\" aria-label=\"")
1571+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 142, "<table class=\"dt spl\" aria-label=\"")
14861572 if templ_7745c5c3_Err != nil {
14871573 return templ_7745c5c3_Err
14881574 }
1489- var templ_7745c5c3_Var76 string
1490- templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", split")
1575+ var templ_7745c5c3_Var80 string
1576+ templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", split")
14911577 if templ_7745c5c3_Err != nil {
1492- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 258, Col: 58}
1578+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 276, Col: 58}
14931579 }
1494- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var76)
1580+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
14951581 if templ_7745c5c3_Err != nil {
14961582 return templ_7745c5c3_Err
14971583 }
1498- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 137, "\"><colgroup><col class=\"c-ln\"><col class=\"c-m\"><col><col class=\"c-ln\"><col class=\"c-m\"><col></colgroup> ")
1584+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 143, "\"><colgroup><col class=\"c-ln\"><col class=\"c-m\"><col><col class=\"c-ln\"><col class=\"c-m\"><col></colgroup> ")
14991585 if templ_7745c5c3_Err != nil {
15001586 return templ_7745c5c3_Err
15011587 }
15021588 for _, h := range f.Hunks {
1503- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 138, "<tbody>")
1589+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 144, "<tbody>")
15041590 if templ_7745c5c3_Err != nil {
15051591 return templ_7745c5c3_Err
15061592 }
@@ -1510,25 +1596,25 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
15101596 return templ_7745c5c3_Err
15111597 }
15121598 }
1513- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 139, "<tr class=\"hunk\"><td colspan=\"6\">")
1599+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 145, "<tr class=\"hunk\"><td colspan=\"6\">")
15141600 if templ_7745c5c3_Err != nil {
15151601 return templ_7745c5c3_Err
15161602 }
1517- var templ_7745c5c3_Var77 string
1518- templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
1603+ var templ_7745c5c3_Var81 string
1604+ templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
15191605 if templ_7745c5c3_Err != nil {
1520- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 265, Col: 51}
1606+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 283, Col: 51}
15211607 }
1522- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77))
1608+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
15231609 if templ_7745c5c3_Err != nil {
15241610 return templ_7745c5c3_Err
15251611 }
1526- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 140, "</td></tr>")
1612+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 146, "</td></tr>")
15271613 if templ_7745c5c3_Err != nil {
15281614 return templ_7745c5c3_Err
15291615 }
15301616 for _, row := range h.Split {
1531- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 141, "<tr>")
1617+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 147, "<tr>")
15321618 if templ_7745c5c3_Err != nil {
15331619 return templ_7745c5c3_Err
15341620 }
@@ -1540,12 +1626,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
15401626 if templ_7745c5c3_Err != nil {
15411627 return templ_7745c5c3_Err
15421628 }
1543- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 142, "</tr>")
1629+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 148, "</tr>")
15441630 if templ_7745c5c3_Err != nil {
15451631 return templ_7745c5c3_Err
15461632 }
15471633 if notes, form := row.Notes(), row.Form(); len(notes) > 0 || form != nil {
1548- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 143, "<tr class=\"fnote\"><td colspan=\"6\">")
1634+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 149, "<tr class=\"fnote\"><td colspan=\"6\">")
15491635 if templ_7745c5c3_Err != nil {
15501636 return templ_7745c5c3_Err
15511637 }
@@ -1553,19 +1639,19 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
15531639 if templ_7745c5c3_Err != nil {
15541640 return templ_7745c5c3_Err
15551641 }
1556- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 144, "</td></tr>")
1642+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 150, "</td></tr>")
15571643 if templ_7745c5c3_Err != nil {
15581644 return templ_7745c5c3_Err
15591645 }
15601646 }
15611647 }
1562- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 145, "</tbody> ")
1648+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 151, "</tbody> ")
15631649 if templ_7745c5c3_Err != nil {
15641650 return templ_7745c5c3_Err
15651651 }
15661652 }
15671653 if f.Tail != nil {
1568- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 146, "<tbody>")
1654+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 152, "<tbody>")
15691655 if templ_7745c5c3_Err != nil {
15701656 return templ_7745c5c3_Err
15711657 }
@@ -1573,48 +1659,48 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
15731659 if templ_7745c5c3_Err != nil {
15741660 return templ_7745c5c3_Err
15751661 }
1576- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 147, "</tbody>")
1662+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 153, "</tbody>")
15771663 if templ_7745c5c3_Err != nil {
15781664 return templ_7745c5c3_Err
15791665 }
15801666 }
1581- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 148, "</table>")
1667+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 154, "</table>")
15821668 if templ_7745c5c3_Err != nil {
15831669 return templ_7745c5c3_Err
15841670 }
15851671 }
1586- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 149, "</div>")
1672+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 155, "</div>")
15871673 if templ_7745c5c3_Err != nil {
15881674 return templ_7745c5c3_Err
15891675 }
15901676 } else {
1591- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 150, "<p class=\"note pad\">")
1677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 156, "<p class=\"note pad\">")
15921678 if templ_7745c5c3_Err != nil {
15931679 return templ_7745c5c3_Err
15941680 }
15951681 if f.Note != "" {
1596- var templ_7745c5c3_Var78 string
1597- templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
1682+ var templ_7745c5c3_Var82 string
1683+ templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
15981684 if templ_7745c5c3_Err != nil {
1599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 290, Col: 13}
1685+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 308, Col: 13}
16001686 }
1601- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))
1687+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var82))
16021688 if templ_7745c5c3_Err != nil {
16031689 return templ_7745c5c3_Err
16041690 }
16051691 } else {
1606- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 151, "no textual change.")
1692+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 157, "no textual change.")
16071693 if templ_7745c5c3_Err != nil {
16081694 return templ_7745c5c3_Err
16091695 }
16101696 }
1611- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 152, "</p>")
1697+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 158, "</p>")
16121698 if templ_7745c5c3_Err != nil {
16131699 return templ_7745c5c3_Err
16141700 }
16151701 }
16161702 if len(f.Loose) > 0 {
1617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 153, "<div class=\"dloose\">")
1703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 159, "<div class=\"dloose\">")
16181704 if templ_7745c5c3_Err != nil {
16191705 return templ_7745c5c3_Err
16201706 }
@@ -1624,12 +1710,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
16241710 return templ_7745c5c3_Err
16251711 }
16261712 }
1627- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 154, "</div>")
1713+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 160, "</div>")
16281714 if templ_7745c5c3_Err != nil {
16291715 return templ_7745c5c3_Err
16301716 }
16311717 }
1632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 155, "</details>")
1718+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 161, "</details>")
16331719 if templ_7745c5c3_Err != nil {
16341720 return templ_7745c5c3_Err
16351721 }
@@ -1655,9 +1741,9 @@ func MRFiles(p MRFilesPage) templ.Component {
16551741 }()
16561742 }
16571743 ctx = templ.InitializeContext(ctx)
1658- templ_7745c5c3_Var79 := templ.GetChildren(ctx)
1659- if templ_7745c5c3_Var79 == nil {
1660- templ_7745c5c3_Var79 = templ.NopComponent
1744+ templ_7745c5c3_Var83 := templ.GetChildren(ctx)
1745+ if templ_7745c5c3_Var83 == nil {
1746+ templ_7745c5c3_Var83 = templ.NopComponent
16611747 }
16621748 ctx = templ.ClearChildren(ctx)
16631749 for _, f := range p.Files {
@@ -1688,12 +1774,12 @@ func MRFilesMoved() templ.Component {
16881774 }()
16891775 }
16901776 ctx = templ.InitializeContext(ctx)
1691- templ_7745c5c3_Var80 := templ.GetChildren(ctx)
1692- if templ_7745c5c3_Var80 == nil {
1693- templ_7745c5c3_Var80 = templ.NopComponent
1777+ templ_7745c5c3_Var84 := templ.GetChildren(ctx)
1778+ if templ_7745c5c3_Var84 == nil {
1779+ templ_7745c5c3_Var84 = templ.NopComponent
16941780 }
16951781 ctx = templ.ClearChildren(ctx)
1696- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 156, "<p class=\"notice\" data-moved>this merge request changed since the page was loaded — <a href=\"\">reload</a></p>")
1782+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 162, "<p class=\"notice\" data-moved>this merge request changed since the page was loaded — <a href=\"\">reload</a></p>")
16971783 if templ_7745c5c3_Err != nil {
16981784 return templ_7745c5c3_Err
16991785 }
@@ -1720,64 +1806,64 @@ func gapRow(g DiffGap, cols int) templ.Component {
17201806 }()
17211807 }
17221808 ctx = templ.InitializeContext(ctx)
1723- templ_7745c5c3_Var81 := templ.GetChildren(ctx)
1724- if templ_7745c5c3_Var81 == nil {
1725- templ_7745c5c3_Var81 = templ.NopComponent
1809+ templ_7745c5c3_Var85 := templ.GetChildren(ctx)
1810+ if templ_7745c5c3_Var85 == nil {
1811+ templ_7745c5c3_Var85 = templ.NopComponent
17261812 }
17271813 ctx = templ.ClearChildren(ctx)
1728- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 157, "<tr class=\"gap\" data-js data-gap=\"")
1814+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 163, "<tr class=\"gap\" data-js data-gap=\"")
17291815 if templ_7745c5c3_Err != nil {
17301816 return templ_7745c5c3_Err
17311817 }
1732- var templ_7745c5c3_Var82 string
1733- templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Key)
1818+ var templ_7745c5c3_Var86 string
1819+ templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Key)
17341820 if templ_7745c5c3_Err != nil {
1735- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 324, Col: 41}
1821+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 342, Col: 41}
17361822 }
1737- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)
1823+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var86)
17381824 if templ_7745c5c3_Err != nil {
17391825 return templ_7745c5c3_Err
17401826 }
1741- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 158, "\"><td colspan=\"")
1827+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 164, "\"><td colspan=\"")
17421828 if templ_7745c5c3_Err != nil {
17431829 return templ_7745c5c3_Err
17441830 }
1745- var templ_7745c5c3_Var83 string
1746- templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(cols))
1831+ var templ_7745c5c3_Var87 string
1832+ templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(cols))
17471833 if templ_7745c5c3_Err != nil {
1748- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 325, Col: 26}
1834+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 343, Col: 26}
17491835 }
1750- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)
1836+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
17511837 if templ_7745c5c3_Err != nil {
17521838 return templ_7745c5c3_Err
17531839 }
1754- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 159, "\"><button type=\"button\" data-src=\"")
1840+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 165, "\"><button type=\"button\" data-src=\"")
17551841 if templ_7745c5c3_Err != nil {
17561842 return templ_7745c5c3_Err
17571843 }
1758- var templ_7745c5c3_Var84 string
1759- templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Src)
1844+ var templ_7745c5c3_Var88 string
1845+ templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Src)
17601846 if templ_7745c5c3_Err != nil {
1761- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 326, Col: 41}
1847+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 344, Col: 41}
17621848 }
1763- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var84)
1849+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var88)
17641850 if templ_7745c5c3_Err != nil {
17651851 return templ_7745c5c3_Err
17661852 }
1767- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 160, "\"><span aria-hidden=\"true\">⋯</span> ")
1853+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 166, "\"><span aria-hidden=\"true\">⋯</span> ")
17681854 if templ_7745c5c3_Err != nil {
17691855 return templ_7745c5c3_Err
17701856 }
1771- var templ_7745c5c3_Var85 string
1772- templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(g.Label())
1857+ var templ_7745c5c3_Var89 string
1858+ templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(g.Label())
17731859 if templ_7745c5c3_Err != nil {
1774- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 327, Col: 51}
1860+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 345, Col: 51}
17751861 }
1776- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85))
1862+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
17771863 if templ_7745c5c3_Err != nil {
17781864 return templ_7745c5c3_Err
17791865 }
1780- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 161, "</button></td></tr>")
1866+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 167, "</button></td></tr>")
17811867 if templ_7745c5c3_Err != nil {
17821868 return templ_7745c5c3_Err
17831869 }
@@ -1803,56 +1889,56 @@ func DiffContext(c ContextRows) templ.Component {
18031889 }()
18041890 }
18051891 ctx = templ.InitializeContext(ctx)
1806- templ_7745c5c3_Var86 := templ.GetChildren(ctx)
1807- if templ_7745c5c3_Var86 == nil {
1808- templ_7745c5c3_Var86 = templ.NopComponent
1892+ templ_7745c5c3_Var90 := templ.GetChildren(ctx)
1893+ if templ_7745c5c3_Var90 == nil {
1894+ templ_7745c5c3_Var90 = templ.NopComponent
18091895 }
18101896 ctx = templ.ClearChildren(ctx)
1811- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 162, "<table><tbody data-for=\"uni\">")
1897+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 168, "<table><tbody data-for=\"uni\">")
18121898 if templ_7745c5c3_Err != nil {
18131899 return templ_7745c5c3_Err
18141900 }
18151901 for _, ln := range c.Lines {
1816- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 163, "<tr class=\"ctx\"><td class=\"ln\">")
1902+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 169, "<tr class=\"ctx\"><td class=\"ln\">")
18171903 if templ_7745c5c3_Err != nil {
18181904 return templ_7745c5c3_Err
18191905 }
1820- var templ_7745c5c3_Var87 string
1821- templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Old)
1906+ var templ_7745c5c3_Var91 string
1907+ templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Old)
18221908 if templ_7745c5c3_Err != nil {
1823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 340, Col: 28}
1909+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 358, Col: 28}
18241910 }
1825- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87))
1911+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91))
18261912 if templ_7745c5c3_Err != nil {
18271913 return templ_7745c5c3_Err
18281914 }
1829- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 164, "</td><td class=\"ln\">")
1915+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 170, "</td><td class=\"ln\">")
18301916 if templ_7745c5c3_Err != nil {
18311917 return templ_7745c5c3_Err
18321918 }
1833- var templ_7745c5c3_Var88 string
1834- templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(ln.New)
1919+ var templ_7745c5c3_Var92 string
1920+ templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.JoinStringErrs(ln.New)
18351921 if templ_7745c5c3_Err != nil {
1836- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 341, Col: 28}
1922+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 359, Col: 28}
18371923 }
1838- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
1924+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var92))
18391925 if templ_7745c5c3_Err != nil {
18401926 return templ_7745c5c3_Err
18411927 }
1842- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 165, "</td><td class=\"m\">")
1928+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 171, "</td><td class=\"m\">")
18431929 if templ_7745c5c3_Err != nil {
18441930 return templ_7745c5c3_Err
18451931 }
1846- var templ_7745c5c3_Var89 string
1847- templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
1932+ var templ_7745c5c3_Var93 string
1933+ templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
18481934 if templ_7745c5c3_Err != nil {
1849- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 342, Col: 28}
1935+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 360, Col: 28}
18501936 }
1851- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
1937+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93))
18521938 if templ_7745c5c3_Err != nil {
18531939 return templ_7745c5c3_Err
18541940 }
1855- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 166, "</td><td class=\"tx chroma\">")
1941+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 172, "</td><td class=\"tx chroma\">")
18561942 if templ_7745c5c3_Err != nil {
18571943 return templ_7745c5c3_Err
18581944 }
@@ -1860,7 +1946,7 @@ func DiffContext(c ContextRows) templ.Component {
18601946 if templ_7745c5c3_Err != nil {
18611947 return templ_7745c5c3_Err
18621948 }
1863- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 167, "</td></tr>")
1949+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "</td></tr>")
18641950 if templ_7745c5c3_Err != nil {
18651951 return templ_7745c5c3_Err
18661952 }
@@ -1871,12 +1957,12 @@ func DiffContext(c ContextRows) templ.Component {
18711957 return templ_7745c5c3_Err
18721958 }
18731959 }
1874- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 168, "</tbody> <tbody data-for=\"spl\">")
1960+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, "</tbody> <tbody data-for=\"spl\">")
18751961 if templ_7745c5c3_Err != nil {
18761962 return templ_7745c5c3_Err
18771963 }
18781964 for i := range c.Lines {
1879- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 169, "<tr>")
1965+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 175, "<tr>")
18801966 if templ_7745c5c3_Err != nil {
18811967 return templ_7745c5c3_Err
18821968 }
@@ -1888,7 +1974,7 @@ func DiffContext(c ContextRows) templ.Component {
18881974 if templ_7745c5c3_Err != nil {
18891975 return templ_7745c5c3_Err
18901976 }
1891- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 170, "</tr>")
1977+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 176, "</tr>")
18921978 if templ_7745c5c3_Err != nil {
18931979 return templ_7745c5c3_Err
18941980 }
@@ -1899,7 +1985,7 @@ func DiffContext(c ContextRows) templ.Component {
18991985 return templ_7745c5c3_Err
19001986 }
19011987 }
1902- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 171, "</tbody></table>")
1988+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, "</tbody></table>")
19031989 if templ_7745c5c3_Err != nil {
19041990 return templ_7745c5c3_Err
19051991 }
@@ -1925,36 +2011,36 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
19252011 }()
19262012 }
19272013 ctx = templ.InitializeContext(ctx)
1928- templ_7745c5c3_Var90 := templ.GetChildren(ctx)
1929- if templ_7745c5c3_Var90 == nil {
1930- templ_7745c5c3_Var90 = templ.NopComponent
2014+ templ_7745c5c3_Var94 := templ.GetChildren(ctx)
2015+ if templ_7745c5c3_Var94 == nil {
2016+ templ_7745c5c3_Var94 = templ.NopComponent
19312017 }
19322018 ctx = templ.ClearChildren(ctx)
19332019 if ln == nil {
1934- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 172, "<td class=\"ln none\"></td><td class=\"m none\"></td><td class=\"tx none\"></td>")
2020+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 178, "<td class=\"ln none\"></td><td class=\"m none\"></td><td class=\"tx none\"></td>")
19352021 if templ_7745c5c3_Err != nil {
19362022 return templ_7745c5c3_Err
19372023 }
19382024 } else {
1939- var templ_7745c5c3_Var91 = []any{"ln", ln.Kind, templ.KV("sel", ln.Selected)}
1940- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var91...)
2025+ var templ_7745c5c3_Var95 = []any{"ln", ln.Kind, templ.KV("sel", ln.Selected)}
2026+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var95...)
19412027 if templ_7745c5c3_Err != nil {
19422028 return templ_7745c5c3_Err
19432029 }
1944- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "<td class=\"")
2030+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 179, "<td class=\"")
19452031 if templ_7745c5c3_Err != nil {
19462032 return templ_7745c5c3_Err
19472033 }
1948- var templ_7745c5c3_Var92 string
1949- templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var91).String())
2034+ var templ_7745c5c3_Var96 string
2035+ templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var95).String())
19502036 if templ_7745c5c3_Err != nil {
19512037 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
19522038 }
1953- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)
2039+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var96)
19542040 if templ_7745c5c3_Err != nil {
19552041 return templ_7745c5c3_Err
19562042 }
1957- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, "\">")
2043+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, "\">")
19582044 if templ_7745c5c3_Err != nil {
19592045 return templ_7745c5c3_Err
19602046 }
@@ -1969,64 +2055,64 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
19692055 return templ_7745c5c3_Err
19702056 }
19712057 }
1972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 175, "</td>")
2058+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 181, "</td>")
19732059 if templ_7745c5c3_Err != nil {
19742060 return templ_7745c5c3_Err
19752061 }
1976- var templ_7745c5c3_Var93 = []any{"m", ln.Kind, templ.KV("sel", ln.Selected)}
1977- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var93...)
2062+ var templ_7745c5c3_Var97 = []any{"m", ln.Kind, templ.KV("sel", ln.Selected)}
2063+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var97...)
19782064 if templ_7745c5c3_Err != nil {
19792065 return templ_7745c5c3_Err
19802066 }
1981- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 176, "<td class=\"")
2067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 182, "<td class=\"")
19822068 if templ_7745c5c3_Err != nil {
19832069 return templ_7745c5c3_Err
19842070 }
1985- var templ_7745c5c3_Var94 string
1986- templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var93).String())
2071+ var templ_7745c5c3_Var98 string
2072+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var97).String())
19872073 if templ_7745c5c3_Err != nil {
19882074 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
19892075 }
1990- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)
2076+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var98)
19912077 if templ_7745c5c3_Err != nil {
19922078 return templ_7745c5c3_Err
19932079 }
1994- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, "\">")
2080+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 183, "\">")
19952081 if templ_7745c5c3_Err != nil {
19962082 return templ_7745c5c3_Err
19972083 }
1998- var templ_7745c5c3_Var95 string
1999- templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
2084+ var templ_7745c5c3_Var99 string
2085+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
20002086 if templ_7745c5c3_Err != nil {
2001- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 379, Col: 68}
2087+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 397, Col: 68}
20022088 }
2003- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))
2089+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
20042090 if templ_7745c5c3_Err != nil {
20052091 return templ_7745c5c3_Err
20062092 }
2007- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 178, "</td>")
2093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, "</td>")
20082094 if templ_7745c5c3_Err != nil {
20092095 return templ_7745c5c3_Err
20102096 }
2011- var templ_7745c5c3_Var96 = []any{"tx", "chroma", ln.Kind, templ.KV("sel", ln.Selected)}
2012- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var96...)
2097+ var templ_7745c5c3_Var100 = []any{"tx", "chroma", ln.Kind, templ.KV("sel", ln.Selected)}
2098+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var100...)
20132099 if templ_7745c5c3_Err != nil {
20142100 return templ_7745c5c3_Err
20152101 }
2016- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 179, "<td class=\"")
2102+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<td class=\"")
20172103 if templ_7745c5c3_Err != nil {
20182104 return templ_7745c5c3_Err
20192105 }
2020- var templ_7745c5c3_Var97 string
2021- templ_7745c5c3_Var97, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var96).String())
2106+ var templ_7745c5c3_Var101 string
2107+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var100).String())
20222108 if templ_7745c5c3_Err != nil {
20232109 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
20242110 }
2025- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var97)
2111+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var101)
20262112 if templ_7745c5c3_Err != nil {
20272113 return templ_7745c5c3_Err
20282114 }
2029- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, "\">")
2115+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "\">")
20302116 if templ_7745c5c3_Err != nil {
20312117 return templ_7745c5c3_Err
20322118 }
@@ -2034,7 +2120,7 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
20342120 if templ_7745c5c3_Err != nil {
20352121 return templ_7745c5c3_Err
20362122 }
2037- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 181, "</td>")
2123+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</td>")
20382124 if templ_7745c5c3_Err != nil {
20392125 return templ_7745c5c3_Err
20402126 }
@@ -2061,49 +2147,49 @@ func gutter(n, href string) templ.Component {
20612147 }()
20622148 }
20632149 ctx = templ.InitializeContext(ctx)
2064- templ_7745c5c3_Var98 := templ.GetChildren(ctx)
2065- if templ_7745c5c3_Var98 == nil {
2066- templ_7745c5c3_Var98 = templ.NopComponent
2150+ templ_7745c5c3_Var102 := templ.GetChildren(ctx)
2151+ if templ_7745c5c3_Var102 == nil {
2152+ templ_7745c5c3_Var102 = templ.NopComponent
20672153 }
20682154 ctx = templ.ClearChildren(ctx)
20692155 if href != "" {
2070- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 182, "<a href=\"")
2156+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, "<a href=\"")
20712157 if templ_7745c5c3_Err != nil {
20722158 return templ_7745c5c3_Err
20732159 }
2074- var templ_7745c5c3_Var99 templ.SafeURL
2075- templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
2160+ var templ_7745c5c3_Var103 templ.SafeURL
2161+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
20762162 if templ_7745c5c3_Err != nil {
2077- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 388, Col: 31}
2163+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 406, Col: 31}
20782164 }
2079- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2165+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
20802166 if templ_7745c5c3_Err != nil {
20812167 return templ_7745c5c3_Err
20822168 }
2083- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 183, "\" title=\"comment on this line\">")
2169+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "\" title=\"comment on this line\">")
20842170 if templ_7745c5c3_Err != nil {
20852171 return templ_7745c5c3_Err
20862172 }
2087- var templ_7745c5c3_Var100 string
2088- templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(n)
2173+ var templ_7745c5c3_Var104 string
2174+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(n)
20892175 if templ_7745c5c3_Err != nil {
2090- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 388, Col: 66}
2176+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 406, Col: 66}
20912177 }
2092- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
2178+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
20932179 if templ_7745c5c3_Err != nil {
20942180 return templ_7745c5c3_Err
20952181 }
2096- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, "</a>")
2182+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "</a>")
20972183 if templ_7745c5c3_Err != nil {
20982184 return templ_7745c5c3_Err
20992185 }
21002186 } else {
2101- var templ_7745c5c3_Var101 string
2102- templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(n)
2187+ var templ_7745c5c3_Var105 string
2188+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(n)
21032189 if templ_7745c5c3_Err != nil {
2104- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 390, Col: 5}
2190+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 408, Col: 5}
21052191 }
2106- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
2192+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
21072193 if templ_7745c5c3_Err != nil {
21082194 return templ_7745c5c3_Err
21092195 }
@@ -359,15 +359,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
359 if templ_7745c5c3_Err != nil {359 if templ_7745c5c3_Err != nil {
360 return templ_7745c5c3_Err360 return templ_7745c5c3_Err
361 }361 }
362- templ_7745c5c3_Err = viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref).Render(ctx, templ_7745c5c3_Buffer)362+ templ_7745c5c3_Err = diffViewMenu(p.DiffView).Render(ctx, templ_7745c5c3_Buffer)
363- if templ_7745c5c3_Err != nil {
364- return templ_7745c5c3_Err
365- }
366- templ_7745c5c3_Err = viewLink(p.DiffView, "split", "Split", "d", p.SplitHref).Render(ctx, templ_7745c5c3_Buffer)
367- if templ_7745c5c3_Err != nil {
368- return templ_7745c5c3_Err
369- }
370- templ_7745c5c3_Err = collapseButton().Render(ctx, templ_7745c5c3_Buffer)
371 if templ_7745c5c3_Err != nil {363 if templ_7745c5c3_Err != nil {
372 return templ_7745c5c3_Err364 return templ_7745c5c3_Err
373 }365 }
@@ -393,7 +385,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
393 var templ_7745c5c3_Var17 string385 var templ_7745c5c3_Var17 string
394 templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)386 templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(p.Note)
395 if templ_7745c5c3_Err != nil {387 if templ_7745c5c3_Err != nil {
396- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 86, Col: 29}388+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 84, Col: 29}
397 }389 }
398 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))390 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
399 if templ_7745c5c3_Err != nil {391 if templ_7745c5c3_Err != nil {
@@ -416,7 +408,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
416 var templ_7745c5c3_Var18 string408 var templ_7745c5c3_Var18 string
417 templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)409 templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
418 if templ_7745c5c3_Err != nil {410 if templ_7745c5c3_Err != nil {
419- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 91, Col: 22}411+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 89, Col: 22}
420 }412 }
421 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18)413 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18)
422 if templ_7745c5c3_Err != nil {414 if templ_7745c5c3_Err != nil {
@@ -434,7 +426,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
434 var templ_7745c5c3_Var19 string426 var templ_7745c5c3_Var19 string
435 templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)427 templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(p.View)
436 if templ_7745c5c3_Err != nil {428 if templ_7745c5c3_Err != nil {
437- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 93, Col: 22}429+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 91, Col: 22}
438 }430 }
439 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)431 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)
440 if templ_7745c5c3_Err != nil {432 if templ_7745c5c3_Err != nil {
@@ -469,7 +461,7 @@ func Commit(l Layout, p CommitPage) templ.Component {
469 var templ_7745c5c3_Var20 string461 var templ_7745c5c3_Var20 string
470 templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(" ")462 templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
471 if templ_7745c5c3_Err != nil {463 if templ_7745c5c3_Err != nil {
472- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 103, Col: 41}464+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 101, Col: 41}
473 }465 }
474 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))466 _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
475 if templ_7745c5c3_Err != nil {467 if templ_7745c5c3_Err != nil {
@@ -509,6 +501,87 @@ func Commit(l Layout, p CommitPage) templ.Component {
509 })501 })
510 }502 }
511 503
504+// diffViewMenu is the layout of the diff (unified, the default, or split) and
505+// the fold of its files, in one menu: a <details> that works without scripts;
506+// u, d and x still act without opening it. Its button names the layout shown.
507+func diffViewMenu(p DiffView) templ.Component {
508+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
509+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
510+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
511+ return templ_7745c5c3_CtxErr
512+ }
513+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
514+ if !templ_7745c5c3_IsBuffer {
515+ defer func() {
516+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
517+ if templ_7745c5c3_Err == nil {
518+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
519+ }
520+ }()
521+ }
522+ ctx = templ.InitializeContext(ctx)
523+ templ_7745c5c3_Var21 := templ.GetChildren(ctx)
524+ if templ_7745c5c3_Var21 == nil {
525+ templ_7745c5c3_Var21 = templ.NopComponent
526+ }
527+ ctx = templ.ClearChildren(ctx)
528+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<details class=\"menu vmenu\"><summary class=\"btn\" aria-label=\"Diff view\">")
529+ if templ_7745c5c3_Err != nil {
530+ return templ_7745c5c3_Err
531+ }
532+ if p.Both {
533+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<span hx-live=\"this.textContent = q('#diffs').attr['data-diff'] === 'split' ? 'Split' : 'Unified'\">")
534+ if templ_7745c5c3_Err != nil {
535+ return templ_7745c5c3_Err
536+ }
537+ var templ_7745c5c3_Var22 string
538+ templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(viewLabel(p.View))
539+ if templ_7745c5c3_Err != nil {
540+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 120, Col: 122}
541+ }
542+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
543+ if templ_7745c5c3_Err != nil {
544+ return templ_7745c5c3_Err
545+ }
546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "</span>")
547+ if templ_7745c5c3_Err != nil {
548+ return templ_7745c5c3_Err
549+ }
550+ } else {
551+ var templ_7745c5c3_Var23 string
552+ templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(viewLabel(p.View))
553+ if templ_7745c5c3_Err != nil {
554+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 122, Col: 23}
555+ }
556+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
557+ if templ_7745c5c3_Err != nil {
558+ return templ_7745c5c3_Err
559+ }
560+ }
561+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "</summary><div class=\"menu-pop\" role=\"group\" aria-label=\"Diff view\">")
562+ if templ_7745c5c3_Err != nil {
563+ return templ_7745c5c3_Err
564+ }
565+ templ_7745c5c3_Err = viewLink(p, "unified", "Unified", "u", p.UnifiedHref).Render(ctx, templ_7745c5c3_Buffer)
566+ if templ_7745c5c3_Err != nil {
567+ return templ_7745c5c3_Err
568+ }
569+ templ_7745c5c3_Err = viewLink(p, "split", "Split", "d", p.SplitHref).Render(ctx, templ_7745c5c3_Buffer)
570+ if templ_7745c5c3_Err != nil {
571+ return templ_7745c5c3_Err
572+ }
573+ templ_7745c5c3_Err = collapseButton().Render(ctx, templ_7745c5c3_Buffer)
574+ if templ_7745c5c3_Err != nil {
575+ return templ_7745c5c3_Err
576+ }
577+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</div></details>")
578+ if templ_7745c5c3_Err != nil {
579+ return templ_7745c5c3_Err
580+ }
581+ return nil
582+ })
583+}
584+
512 // viewLink is a button of the diff tools. It is a link, so that the split585 // viewLink is a button of the diff tools. It is a link, so that the split
513 // layout works without JavaScript; with it, and when both layouts are in the586 // layout works without JavaScript; with it, and when both layouts are in the
514 // page, a click only flips the layout.587 // page, a click only flips the layout.
@@ -528,106 +601,106 @@ func viewLink(p DiffView, view, label, key, href string) templ.Component {
528 }()601 }()
529 }602 }
530 ctx = templ.InitializeContext(ctx)603 ctx = templ.InitializeContext(ctx)
531- templ_7745c5c3_Var21 := templ.GetChildren(ctx)604+ templ_7745c5c3_Var24 := templ.GetChildren(ctx)
532- if templ_7745c5c3_Var21 == nil {605+ if templ_7745c5c3_Var24 == nil {
533- templ_7745c5c3_Var21 = templ.NopComponent606+ templ_7745c5c3_Var24 = templ.NopComponent
534 }607 }
535 ctx = templ.ClearChildren(ctx)608 ctx = templ.ClearChildren(ctx)
536- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<a href=\"")609+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "<a href=\"")
537 if templ_7745c5c3_Err != nil {610 if templ_7745c5c3_Err != nil {
538 return templ_7745c5c3_Err611 return templ_7745c5c3_Err
539 }612 }
540- var templ_7745c5c3_Var22 templ.SafeURL613+ var templ_7745c5c3_Var25 templ.SafeURL
541- templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))614+ templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
542 if templ_7745c5c3_Err != nil {615 if templ_7745c5c3_Err != nil {
543- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 120, Col: 28}616+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 138, Col: 28}
544 }617 }
545- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))618+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
546 if templ_7745c5c3_Err != nil {619 if templ_7745c5c3_Err != nil {
547 return templ_7745c5c3_Err620 return templ_7745c5c3_Err
548 }621 }
549- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\" class=\"btn vbtn\" data-view=\"")622+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\" class=\"btn vbtn\" data-view=\"")
550 if templ_7745c5c3_Err != nil {623 if templ_7745c5c3_Err != nil {
551 return templ_7745c5c3_Err624 return templ_7745c5c3_Err
552 }625 }
553- var templ_7745c5c3_Var23 string626+ var templ_7745c5c3_Var26 string
554- templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)627+ templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
555 if templ_7745c5c3_Err != nil {628 if templ_7745c5c3_Err != nil {
556- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 122, Col: 18}629+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 140, Col: 18}
557 }630 }
558- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)631+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var26)
559 if templ_7745c5c3_Err != nil {632 if templ_7745c5c3_Err != nil {
560 return templ_7745c5c3_Err633 return templ_7745c5c3_Err
561 }634 }
562- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" aria-keyshortcuts=\"")635+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "\" aria-keyshortcuts=\"")
563 if templ_7745c5c3_Err != nil {636 if templ_7745c5c3_Err != nil {
564 return templ_7745c5c3_Err637 return templ_7745c5c3_Err
565 }638 }
566- var templ_7745c5c3_Var24 string639+ var templ_7745c5c3_Var27 string
567- templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(key)640+ templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.ResolveAttributeValue(key)
568 if templ_7745c5c3_Err != nil {641 if templ_7745c5c3_Err != nil {
569- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 123, Col: 25}642+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 141, Col: 25}
570 }643 }
571- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24)644+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var27)
572 if templ_7745c5c3_Err != nil {645 if templ_7745c5c3_Err != nil {
573 return templ_7745c5c3_Err646 return templ_7745c5c3_Err
574 }647 }
575- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\"")648+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\"")
576 if templ_7745c5c3_Err != nil {649 if templ_7745c5c3_Err != nil {
577 return templ_7745c5c3_Err650 return templ_7745c5c3_Err
578 }651 }
579 if p.View == view {652 if p.View == view {
580- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, " aria-current=\"true\"")653+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, " aria-current=\"true\"")
581 if templ_7745c5c3_Err != nil {654 if templ_7745c5c3_Err != nil {
582 return templ_7745c5c3_Err655 return templ_7745c5c3_Err
583 }656 }
584 }657 }
585 if p.Both {658 if p.Both {
586- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " data-fire=\"")659+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, " data-fire=\"")
587 if templ_7745c5c3_Err != nil {660 if templ_7745c5c3_Err != nil {
588 return templ_7745c5c3_Err661 return templ_7745c5c3_Err
589 }662 }
590- var templ_7745c5c3_Var25 string663+ var templ_7745c5c3_Var28 string
591- templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)664+ templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(view)
592 if templ_7745c5c3_Err != nil {665 if templ_7745c5c3_Err != nil {
593- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 128, Col: 19}666+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 146, Col: 19}
594 }667 }
595- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var25)668+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)
596 if templ_7745c5c3_Err != nil {669 if templ_7745c5c3_Err != nil {
597 return templ_7745c5c3_Err670 return templ_7745c5c3_Err
598 }671 }
599- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\" :aria-current=\"q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false\"")672+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "\" :aria-current=\"q('#diffs').attr['data-diff'] === this.dataset.view ? 'true' : false\"")
600 if templ_7745c5c3_Err != nil {673 if templ_7745c5c3_Err != nil {
601 return templ_7745c5c3_Err674 return templ_7745c5c3_Err
602 }675 }
603 }676 }
604- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, ">")677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">")
605 if templ_7745c5c3_Err != nil {678 if templ_7745c5c3_Err != nil {
606 return templ_7745c5c3_Err679 return templ_7745c5c3_Err
607 }680 }
608- var templ_7745c5c3_Var26 string681+ var templ_7745c5c3_Var29 string
609- templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(label)682+ templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(label)
610 if templ_7745c5c3_Err != nil {683 if templ_7745c5c3_Err != nil {
611- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 131, Col: 9}684+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 149, Col: 9}
612 }685 }
613- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))686+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
614 if templ_7745c5c3_Err != nil {687 if templ_7745c5c3_Err != nil {
615 return templ_7745c5c3_Err688 return templ_7745c5c3_Err
616 }689 }
617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "<kbd aria-hidden=\"true\">")690+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "<kbd aria-hidden=\"true\">")
618 if templ_7745c5c3_Err != nil {691 if templ_7745c5c3_Err != nil {
619 return templ_7745c5c3_Err692 return templ_7745c5c3_Err
620 }693 }
621- var templ_7745c5c3_Var27 string694+ var templ_7745c5c3_Var30 string
622- templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(key)695+ templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(key)
623 if templ_7745c5c3_Err != nil {696 if templ_7745c5c3_Err != nil {
624- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 131, Col: 40}697+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 149, Col: 40}
625 }698 }
626- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))699+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
627 if templ_7745c5c3_Err != nil {700 if templ_7745c5c3_Err != nil {
628 return templ_7745c5c3_Err701 return templ_7745c5c3_Err
629 }702 }
630- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "</kbd></a>")703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "</kbd></a>")
631 if templ_7745c5c3_Err != nil {704 if templ_7745c5c3_Err != nil {
632 return templ_7745c5c3_Err705 return templ_7745c5c3_Err
633 }706 }
@@ -653,12 +726,12 @@ func collapseButton() templ.Component {
653 }()726 }()
654 }727 }
655 ctx = templ.InitializeContext(ctx)728 ctx = templ.InitializeContext(ctx)
656- templ_7745c5c3_Var28 := templ.GetChildren(ctx)729+ templ_7745c5c3_Var31 := templ.GetChildren(ctx)
657- if templ_7745c5c3_Var28 == nil {730+ if templ_7745c5c3_Var31 == nil {
658- templ_7745c5c3_Var28 = templ.NopComponent731+ templ_7745c5c3_Var31 = templ.NopComponent
659 }732 }
660 ctx = templ.ClearChildren(ctx)733 ctx = templ.ClearChildren(ctx)
661- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "<button type=\"button\" aria-keyshortcuts=\"x\" data-js data-fire=\"collapse\" class=\"btn\"><span hx-live=\"this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'\">Collapse all</span><kbd aria-hidden=\"true\">x</kbd></button>")734+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<button type=\"button\" aria-keyshortcuts=\"x\" data-js data-fire=\"collapse\" class=\"btn\"><span hx-live=\"this.textContent = q('[data-file][open]').count || !q('[data-file]').count ? 'Collapse all' : 'Expand all'\">Collapse all</span><kbd aria-hidden=\"true\">x</kbd></button>")
662 if templ_7745c5c3_Err != nil {735 if templ_7745c5c3_Err != nil {
663 return templ_7745c5c3_Err736 return templ_7745c5c3_Err
664 }737 }
@@ -682,83 +755,83 @@ func personView(pr Person) templ.Component {
682 }()755 }()
683 }756 }
684 ctx = templ.InitializeContext(ctx)757 ctx = templ.InitializeContext(ctx)
685- templ_7745c5c3_Var29 := templ.GetChildren(ctx)758+ templ_7745c5c3_Var32 := templ.GetChildren(ctx)
686- if templ_7745c5c3_Var29 == nil {759+ if templ_7745c5c3_Var32 == nil {
687- templ_7745c5c3_Var29 = templ.NopComponent760+ templ_7745c5c3_Var32 = templ.NopComponent
688 }761 }
689 ctx = templ.ClearChildren(ctx)762 ctx = templ.ClearChildren(ctx)
690- var templ_7745c5c3_Var30 string763+ var templ_7745c5c3_Var33 string
691- templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(pr.Name)764+ templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(pr.Name)
692 if templ_7745c5c3_Err != nil {765 if templ_7745c5c3_Err != nil {
693- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 143, Col: 10}766+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 161, Col: 10}
694 }767 }
695- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))768+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
696 if templ_7745c5c3_Err != nil {769 if templ_7745c5c3_Err != nil {
697 return templ_7745c5c3_Err770 return templ_7745c5c3_Err
698 }771 }
699- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " ")772+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, " ")
700 if templ_7745c5c3_Err != nil {773 if templ_7745c5c3_Err != nil {
701 return templ_7745c5c3_Err774 return templ_7745c5c3_Err
702 }775 }
703 if pr.WhenAt != "" {776 if pr.WhenAt != "" {
704- var templ_7745c5c3_Var31 string777+ var templ_7745c5c3_Var34 string
705- templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")778+ templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(" · ")
706 if templ_7745c5c3_Err != nil {779 if templ_7745c5c3_Err != nil {
707- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 10}780+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 10}
708 }781 }
709- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))782+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
710 if templ_7745c5c3_Err != nil {783 if templ_7745c5c3_Err != nil {
711 return templ_7745c5c3_Err784 return templ_7745c5c3_Err
712 }785 }
713- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "<time datetime=\"")786+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "<time datetime=\"")
714 if templ_7745c5c3_Err != nil {787 if templ_7745c5c3_Err != nil {
715 return templ_7745c5c3_Err788 return templ_7745c5c3_Err
716 }789 }
717- var templ_7745c5c3_Var32 string790+ var templ_7745c5c3_Var35 string
718- templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.WhenAt)791+ templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.WhenAt)
719 if templ_7745c5c3_Err != nil {792 if templ_7745c5c3_Err != nil {
720- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 38}793+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 38}
721 }794 }
722- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var32)795+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var35)
723 if templ_7745c5c3_Err != nil {796 if templ_7745c5c3_Err != nil {
724 return templ_7745c5c3_Err797 return templ_7745c5c3_Err
725 }798 }
726- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "\" title=\"")799+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "\" title=\"")
727 if templ_7745c5c3_Err != nil {800 if templ_7745c5c3_Err != nil {
728 return templ_7745c5c3_Err801 return templ_7745c5c3_Err
729 }802 }
730- var templ_7745c5c3_Var33 string803+ var templ_7745c5c3_Var36 string
731- templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.Abs)804+ templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.ResolveAttributeValue(pr.Abs)
732 if templ_7745c5c3_Err != nil {805 if templ_7745c5c3_Err != nil {
733- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 55}806+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 55}
734 }807 }
735- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var33)808+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var36)
736 if templ_7745c5c3_Err != nil {809 if templ_7745c5c3_Err != nil {
737 return templ_7745c5c3_Err810 return templ_7745c5c3_Err
738 }811 }
739- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "\">")812+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "\">")
740 if templ_7745c5c3_Err != nil {813 if templ_7745c5c3_Err != nil {
741 return templ_7745c5c3_Err814 return templ_7745c5c3_Err
742 }815 }
743- var templ_7745c5c3_Var34 string816+ var templ_7745c5c3_Var37 string
744- templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(pr.When)817+ templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(pr.When)
745 if templ_7745c5c3_Err != nil {818 if templ_7745c5c3_Err != nil {
746- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 67}819+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 67}
747 }820 }
748- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))821+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
749 if templ_7745c5c3_Err != nil {822 if templ_7745c5c3_Err != nil {
750 return templ_7745c5c3_Err823 return templ_7745c5c3_Err
751 }824 }
752- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "</time>")825+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "</time>")
753 if templ_7745c5c3_Err != nil {826 if templ_7745c5c3_Err != nil {
754 return templ_7745c5c3_Err827 return templ_7745c5c3_Err
755 }828 }
756- var templ_7745c5c3_Var35 string829+ var templ_7745c5c3_Var38 string
757- templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + pr.Abs)830+ templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(" · " + pr.Abs)
758 if templ_7745c5c3_Err != nil {831 if templ_7745c5c3_Err != nil {
759- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 145, Col: 93}832+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 163, Col: 93}
760 }833 }
761- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))834+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
762 if templ_7745c5c3_Err != nil {835 if templ_7745c5c3_Err != nil {
763 return templ_7745c5c3_Err836 return templ_7745c5c3_Err
764 }837 }
@@ -783,25 +856,25 @@ func commitRail(p CommitPage) templ.Component {
783 }()856 }()
784 }857 }
785 ctx = templ.InitializeContext(ctx)858 ctx = templ.InitializeContext(ctx)
786- templ_7745c5c3_Var36 := templ.GetChildren(ctx)859+ templ_7745c5c3_Var39 := templ.GetChildren(ctx)
787- if templ_7745c5c3_Var36 == nil {860+ if templ_7745c5c3_Var39 == nil {
788- templ_7745c5c3_Var36 = templ.NopComponent861+ templ_7745c5c3_Var39 = templ.NopComponent
789 }862 }
790 ctx = templ.ClearChildren(ctx)863 ctx = templ.ClearChildren(ctx)
791- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")864+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "<section aria-labelledby=\"r-files\"><h2 id=\"r-files\">Files <span class=\"count\">")
792 if templ_7745c5c3_Err != nil {865 if templ_7745c5c3_Err != nil {
793 return templ_7745c5c3_Err866 return templ_7745c5c3_Err
794 }867 }
795- var templ_7745c5c3_Var37 string868+ var templ_7745c5c3_Var40 string
796- templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))869+ templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(len(p.Files)))
797 if templ_7745c5c3_Err != nil {870 if templ_7745c5c3_Err != nil {
798- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 151, Col: 65}871+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 169, Col: 65}
799 }872 }
800- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))873+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40))
801 if templ_7745c5c3_Err != nil {874 if templ_7745c5c3_Err != nil {
802 return templ_7745c5c3_Err875 return templ_7745c5c3_Err
803 }876 }
804- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "</span></h2>")877+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</span></h2>")
805 if templ_7745c5c3_Err != nil {878 if templ_7745c5c3_Err != nil {
806 return templ_7745c5c3_Err879 return templ_7745c5c3_Err
807 }880 }
@@ -809,7 +882,7 @@ func commitRail(p CommitPage) templ.Component {
809 if templ_7745c5c3_Err != nil {882 if templ_7745c5c3_Err != nil {
810 return templ_7745c5c3_Err883 return templ_7745c5c3_Err
811 }884 }
812- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "</section>")885+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</section>")
813 if templ_7745c5c3_Err != nil {886 if templ_7745c5c3_Err != nil {
814 return templ_7745c5c3_Err887 return templ_7745c5c3_Err
815 }888 }
@@ -835,236 +908,236 @@ func FileList(files []DiffFile) templ.Component {
835 }()908 }()
836 }909 }
837 ctx = templ.InitializeContext(ctx)910 ctx = templ.InitializeContext(ctx)
838- templ_7745c5c3_Var38 := templ.GetChildren(ctx)911+ templ_7745c5c3_Var41 := templ.GetChildren(ctx)
839- if templ_7745c5c3_Var38 == nil {912+ if templ_7745c5c3_Var41 == nil {
840- templ_7745c5c3_Var38 = templ.NopComponent913+ templ_7745c5c3_Var41 = templ.NopComponent
841 }914 }
842 ctx = templ.ClearChildren(ctx)915 ctx = templ.ClearChildren(ctx)
843 if len(files) > fileFilterMin {916 if len(files) > fileFilterMin {
844- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<div class=\"ffilter\"><label for=\"files-filter\" class=\"sr\">filter the changed files</label> <input id=\"files-filter\" type=\"search\" placeholder=\"Filter files…\" autocomplete=\"off\" data-pick=\".files > li\" hx-on:input=\"ermite.filter(this)\"></div>")917+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "<div class=\"ffilter\"><label for=\"files-filter\" class=\"sr\">filter the changed files</label> <input id=\"files-filter\" type=\"search\" placeholder=\"Filter files…\" autocomplete=\"off\" data-pick=\".files > li\" hx-on:input=\"ermite.filter(this)\"></div>")
845 if templ_7745c5c3_Err != nil {918 if templ_7745c5c3_Err != nil {
846 return templ_7745c5c3_Err919 return templ_7745c5c3_Err
847 }920 }
848 }921 }
849- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<ol class=\"files\" aria-label=\"Changed files\">")922+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<ol class=\"files\" aria-label=\"Changed files\">")
850 if templ_7745c5c3_Err != nil {923 if templ_7745c5c3_Err != nil {
851 return templ_7745c5c3_Err924 return templ_7745c5c3_Err
852 }925 }
853 for _, f := range files {926 for _, f := range files {
854- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "<li><a href=\"")927+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "<li><a href=\"")
855 if templ_7745c5c3_Err != nil {928 if templ_7745c5c3_Err != nil {
856 return templ_7745c5c3_Err929 return templ_7745c5c3_Err
857 }930 }
858- var templ_7745c5c3_Var39 templ.SafeURL931+ var templ_7745c5c3_Var42 templ.SafeURL
859- templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("#" + f.ID))932+ templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("#" + f.ID))
860 if templ_7745c5c3_Err != nil {933 if templ_7745c5c3_Err != nil {
861- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 176, Col: 37}934+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 194, Col: 37}
862 }935 }
863- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))936+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
864 if templ_7745c5c3_Err != nil {937 if templ_7745c5c3_Err != nil {
865 return templ_7745c5c3_Err938 return templ_7745c5c3_Err
866 }939 }
867- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "\" title=\"")940+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\" title=\"")
868 if templ_7745c5c3_Err != nil {941 if templ_7745c5c3_Err != nil {
869 return templ_7745c5c3_Err942 return templ_7745c5c3_Err
870 }943 }
871- var templ_7745c5c3_Var40 string944+ var templ_7745c5c3_Var43 string
872- templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)945+ templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path)
873 if templ_7745c5c3_Err != nil {946 if templ_7745c5c3_Err != nil {
874- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 177, Col: 19}947+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 195, Col: 19}
875 }948 }
876- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)949+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var43)
877 if templ_7745c5c3_Err != nil {950 if templ_7745c5c3_Err != nil {
878 return templ_7745c5c3_Err951 return templ_7745c5c3_Err
879 }952 }
880- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "\" hx-on:click=\"(window.ermiteMR?.openFile || ermite.openFile)(this.hash.slice(1))\"><span class=\"st\" data-st=\"")953+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\" hx-on:click=\"(window.ermiteMR?.openFile || ermite.openFile)(this.hash.slice(1))\"><span class=\"st\" data-st=\"")
881 if templ_7745c5c3_Err != nil {954 if templ_7745c5c3_Err != nil {
882 return templ_7745c5c3_Err955 return templ_7745c5c3_Err
883 }956 }
884- var templ_7745c5c3_Var41 string957+ var templ_7745c5c3_Var44 string
885- templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Status)958+ templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Status)
886 if templ_7745c5c3_Err != nil {959 if templ_7745c5c3_Err != nil {
887- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 40}960+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 40}
888 }961 }
889- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var41)962+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var44)
890 if templ_7745c5c3_Err != nil {963 if templ_7745c5c3_Err != nil {
891 return templ_7745c5c3_Err964 return templ_7745c5c3_Err
892 }965 }
893- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "\" title=\"")966+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" title=\"")
894 if templ_7745c5c3_Err != nil {967 if templ_7745c5c3_Err != nil {
895 return templ_7745c5c3_Err968 return templ_7745c5c3_Err
896 }969 }
897- var templ_7745c5c3_Var42 string970+ var templ_7745c5c3_Var45 string
898- templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.ResolveAttributeValue(statusName(f.Status))971+ templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.ResolveAttributeValue(statusName(f.Status))
899 if templ_7745c5c3_Err != nil {972 if templ_7745c5c3_Err != nil {
900- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 71}973+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 71}
901 }974 }
902- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var42)975+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var45)
903 if templ_7745c5c3_Err != nil {976 if templ_7745c5c3_Err != nil {
904 return templ_7745c5c3_Err977 return templ_7745c5c3_Err
905 }978 }
906- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "\">")979+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "\">")
907 if templ_7745c5c3_Err != nil {980 if templ_7745c5c3_Err != nil {
908 return templ_7745c5c3_Err981 return templ_7745c5c3_Err
909 }982 }
910- var templ_7745c5c3_Var43 string983+ var templ_7745c5c3_Var46 string
911- templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)984+ templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
912 if templ_7745c5c3_Err != nil {985 if templ_7745c5c3_Err != nil {
913- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 180, Col: 84}986+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 198, Col: 84}
914 }987 }
915- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))988+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
916 if templ_7745c5c3_Err != nil {989 if templ_7745c5c3_Err != nil {
917 return templ_7745c5c3_Err990 return templ_7745c5c3_Err
918 }991 }
919- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</span> <span class=\"nm\"><span class=\"p\">")992+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "</span> <span class=\"nm\"><span class=\"p\">")
920 if templ_7745c5c3_Err != nil {993 if templ_7745c5c3_Err != nil {
921 return templ_7745c5c3_Err994 return templ_7745c5c3_Err
922 }995 }
923- var templ_7745c5c3_Var44 string996+ var templ_7745c5c3_Var47 string
924- templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(f.Name)997+ templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(f.Name)
925 if templ_7745c5c3_Err != nil {998 if templ_7745c5c3_Err != nil {
926- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 46}999+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 46}
927 }1000 }
928- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))1001+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
929 if templ_7745c5c3_Err != nil {1002 if templ_7745c5c3_Err != nil {
930 return templ_7745c5c3_Err1003 return templ_7745c5c3_Err
931 }1004 }
932- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "</span>")1005+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</span>")
933 if templ_7745c5c3_Err != nil {1006 if templ_7745c5c3_Err != nil {
934 return templ_7745c5c3_Err1007 return templ_7745c5c3_Err
935 }1008 }
936- var templ_7745c5c3_Var45 string1009+ var templ_7745c5c3_Var48 string
937- templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1010+ templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
938 if templ_7745c5c3_Err != nil {1011 if templ_7745c5c3_Err != nil {
939- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 60}1012+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 60}
940 }1013 }
941- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))1014+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
942 if templ_7745c5c3_Err != nil {1015 if templ_7745c5c3_Err != nil {
943 return templ_7745c5c3_Err1016 return templ_7745c5c3_Err
944 }1017 }
945- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<span class=\"d\"><bdi>")1018+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<span class=\"d\"><bdi>")
946 if templ_7745c5c3_Err != nil {1019 if templ_7745c5c3_Err != nil {
947 return templ_7745c5c3_Err1020 return templ_7745c5c3_Err
948 }1021 }
949- var templ_7745c5c3_Var46 string1022+ var templ_7745c5c3_Var49 string
950- templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(f.Dir)1023+ templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(f.Dir)
951 if templ_7745c5c3_Err != nil {1024 if templ_7745c5c3_Err != nil {
952- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 181, Col: 90}1025+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 199, Col: 90}
953 }1026 }
954- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))1027+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
955 if templ_7745c5c3_Err != nil {1028 if templ_7745c5c3_Err != nil {
956 return templ_7745c5c3_Err1029 return templ_7745c5c3_Err
957 }1030 }
958- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</bdi></span></span> ")1031+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</bdi></span></span> ")
959 if templ_7745c5c3_Err != nil {1032 if templ_7745c5c3_Err != nil {
960 return templ_7745c5c3_Err1033 return templ_7745c5c3_Err
961 }1034 }
962 if f.OpenNotes > 0 {1035 if f.OpenNotes > 0 {
963- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<span class=\"cn\" title=\"")1036+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<span class=\"cn\" title=\"")
964 if templ_7745c5c3_Err != nil {1037 if templ_7745c5c3_Err != nil {
965 return templ_7745c5c3_Err1038 return templ_7745c5c3_Err
966 }1039 }
967- var templ_7745c5c3_Var47 string1040+ var templ_7745c5c3_Var50 string
968- templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.OpenNotes, "open comment", "open comments"))1041+ templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.OpenNotes, "open comment", "open comments"))
969 if templ_7745c5c3_Err != nil {1042 if templ_7745c5c3_Err != nil {
970- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 183, Col: 83}1043+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 201, Col: 83}
971 }1044 }
972- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var47)1045+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)
973 if templ_7745c5c3_Err != nil {1046 if templ_7745c5c3_Err != nil {
974 return templ_7745c5c3_Err1047 return templ_7745c5c3_Err
975 }1048 }
976- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\">")1049+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "\">")
977 if templ_7745c5c3_Err != nil {1050 if templ_7745c5c3_Err != nil {
978 return templ_7745c5c3_Err1051 return templ_7745c5c3_Err
979 }1052 }
980- var templ_7745c5c3_Var48 string1053+ var templ_7745c5c3_Var51 string
981- templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.OpenNotes))1054+ templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.OpenNotes))
982 if templ_7745c5c3_Err != nil {1055 if templ_7745c5c3_Err != nil {
983- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 183, Col: 105}1056+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 201, Col: 105}
984 }1057 }
985- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))1058+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
986 if templ_7745c5c3_Err != nil {1059 if templ_7745c5c3_Err != nil {
987 return templ_7745c5c3_Err1060 return templ_7745c5c3_Err
988 }1061 }
989- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</span> ")1062+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</span> ")
990 if templ_7745c5c3_Err != nil {1063 if templ_7745c5c3_Err != nil {
991 return templ_7745c5c3_Err1064 return templ_7745c5c3_Err
992 }1065 }
993 } else if f.Notes > 0 {1066 } else if f.Notes > 0 {
994- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "<span class=\"cn done\" title=\"")1067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "<span class=\"cn done\" title=\"")
995 if templ_7745c5c3_Err != nil {1068 if templ_7745c5c3_Err != nil {
996 return templ_7745c5c3_Err1069 return templ_7745c5c3_Err
997 }1070 }
998- var templ_7745c5c3_Var49 string1071+ var templ_7745c5c3_Var52 string
999- templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.Notes, "resolved comment", "resolved comments"))1072+ templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(plural(f.Notes, "resolved comment", "resolved comments"))
1000 if templ_7745c5c3_Err != nil {1073 if templ_7745c5c3_Err != nil {
1001- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 185, Col: 92}1074+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 203, Col: 92}
1002 }1075 }
1003- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)1076+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
1004 if templ_7745c5c3_Err != nil {1077 if templ_7745c5c3_Err != nil {
1005 return templ_7745c5c3_Err1078 return templ_7745c5c3_Err
1006 }1079 }
1007- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "\">")1080+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "\">")
1008 if templ_7745c5c3_Err != nil {1081 if templ_7745c5c3_Err != nil {
1009 return templ_7745c5c3_Err1082 return templ_7745c5c3_Err
1010 }1083 }
1011- var templ_7745c5c3_Var50 string1084+ var templ_7745c5c3_Var53 string
1012- templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Notes))1085+ templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Notes))
1013 if templ_7745c5c3_Err != nil {1086 if templ_7745c5c3_Err != nil {
1014- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 185, Col: 110}1087+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 203, Col: 110}
1015 }1088 }
1016- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))1089+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53))
1017 if templ_7745c5c3_Err != nil {1090 if templ_7745c5c3_Err != nil {
1018 return templ_7745c5c3_Err1091 return templ_7745c5c3_Err
1019 }1092 }
1020- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "</span> ")1093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</span> ")
1021 if templ_7745c5c3_Err != nil {1094 if templ_7745c5c3_Err != nil {
1022 return templ_7745c5c3_Err1095 return templ_7745c5c3_Err
1023 }1096 }
1024 }1097 }
1025 if f.Bin {1098 if f.Bin {
1026- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "<span class=\"n mute\">bin</span>")1099+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "<span class=\"n mute\">bin</span>")
1027 if templ_7745c5c3_Err != nil {1100 if templ_7745c5c3_Err != nil {
1028 return templ_7745c5c3_Err1101 return templ_7745c5c3_Err
1029 }1102 }
1030 } else {1103 } else {
1031- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "<span class=\"n\"><span class=\"plus\">+")1104+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<span class=\"n\"><span class=\"plus\">+")
1032 if templ_7745c5c3_Err != nil {1105 if templ_7745c5c3_Err != nil {
1033 return templ_7745c5c3_Err1106 return templ_7745c5c3_Err
1034 }1107 }
1035- var templ_7745c5c3_Var51 string1108+ var templ_7745c5c3_Var54 string
1036- templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))1109+ templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
1037 if templ_7745c5c3_Err != nil {1110 if templ_7745c5c3_Err != nil {
1038- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 190, Col: 55}1111+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 208, Col: 55}
1039 }1112 }
1040- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))1113+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
1041 if templ_7745c5c3_Err != nil {1114 if templ_7745c5c3_Err != nil {
1042 return templ_7745c5c3_Err1115 return templ_7745c5c3_Err
1043 }1116 }
1044- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "</span> <span class=\"minus\">-")1117+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "</span> <span class=\"minus\">-")
1045 if templ_7745c5c3_Err != nil {1118 if templ_7745c5c3_Err != nil {
1046 return templ_7745c5c3_Err1119 return templ_7745c5c3_Err
1047 }1120 }
1048- var templ_7745c5c3_Var52 string1121+ var templ_7745c5c3_Var55 string
1049- templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))1122+ templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
1050 if templ_7745c5c3_Err != nil {1123 if templ_7745c5c3_Err != nil {
1051- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 190, Col: 99}1124+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 208, Col: 99}
1052 }1125 }
1053- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))1126+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
1054 if templ_7745c5c3_Err != nil {1127 if templ_7745c5c3_Err != nil {
1055 return templ_7745c5c3_Err1128 return templ_7745c5c3_Err
1056 }1129 }
1057- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "</span></span>")1130+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "</span></span>")
1058 if templ_7745c5c3_Err != nil {1131 if templ_7745c5c3_Err != nil {
1059 return templ_7745c5c3_Err1132 return templ_7745c5c3_Err
1060 }1133 }
1061 }1134 }
1062- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "</a></li>")1135+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "</a></li>")
1063 if templ_7745c5c3_Err != nil {1136 if templ_7745c5c3_Err != nil {
1064 return templ_7745c5c3_Err1137 return templ_7745c5c3_Err
1065 }1138 }
1066 }1139 }
1067- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "</ol>")1140+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "</ol>")
1068 if templ_7745c5c3_Err != nil {1141 if templ_7745c5c3_Err != nil {
1069 return templ_7745c5c3_Err1142 return templ_7745c5c3_Err
1070 }1143 }
@@ -1092,270 +1165,283 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1092 }()1165 }()
1093 }1166 }
1094 ctx = templ.InitializeContext(ctx)1167 ctx = templ.InitializeContext(ctx)
1095- templ_7745c5c3_Var53 := templ.GetChildren(ctx)1168+ templ_7745c5c3_Var56 := templ.GetChildren(ctx)
1096- if templ_7745c5c3_Var53 == nil {1169+ if templ_7745c5c3_Var56 == nil {
1097- templ_7745c5c3_Var53 = templ.NopComponent1170+ templ_7745c5c3_Var56 = templ.NopComponent
1098 }1171 }
1099 ctx = templ.ClearChildren(ctx)1172 ctx = templ.ClearChildren(ctx)
1100- var templ_7745c5c3_Var54 = []any{"dfile", "lnw-" + itoa(f.Digits)}1173+ var templ_7745c5c3_Var57 = []any{"dfile", "lnw-" + itoa(f.Digits)}
1101- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var54...)1174+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var57...)
1102 if templ_7745c5c3_Err != nil {1175 if templ_7745c5c3_Err != nil {
1103 return templ_7745c5c3_Err1176 return templ_7745c5c3_Err
1104 }1177 }
1105- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "<details class=\"")1178+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "<details class=\"")
1106 if templ_7745c5c3_Err != nil {1179 if templ_7745c5c3_Err != nil {
1107 return templ_7745c5c3_Err1180 return templ_7745c5c3_Err
1108 }1181 }
1109- var templ_7745c5c3_Var55 string1182+ var templ_7745c5c3_Var58 string
1110- templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var54).String())1183+ templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var57).String())
1111 if templ_7745c5c3_Err != nil {1184 if templ_7745c5c3_Err != nil {
1112 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}1185 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
1113 }1186 }
1114- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var55)1187+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var58)
1115 if templ_7745c5c3_Err != nil {1188 if templ_7745c5c3_Err != nil {
1116 return templ_7745c5c3_Err1189 return templ_7745c5c3_Err
1117 }1190 }
1118- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "\" id=\"")1191+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "\" id=\"")
1119 if templ_7745c5c3_Err != nil {1192 if templ_7745c5c3_Err != nil {
1120 return templ_7745c5c3_Err1193 return templ_7745c5c3_Err
1121 }1194 }
1122- var templ_7745c5c3_Var56 string1195+ var templ_7745c5c3_Var59 string
1123- templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID)1196+ templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.ID)
1124 if templ_7745c5c3_Err != nil {1197 if templ_7745c5c3_Err != nil {
1125- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 205, Col: 11}1198+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 223, Col: 11}
1126 }1199 }
1127- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var56)1200+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var59)
1128 if templ_7745c5c3_Err != nil {1201 if templ_7745c5c3_Err != nil {
1129 return templ_7745c5c3_Err1202 return templ_7745c5c3_Err
1130 }1203 }
1131- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "\" data-file")1204+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\" data-file=\"")
1205+ if templ_7745c5c3_Err != nil {
1206+ return templ_7745c5c3_Err
1207+ }
1208+ var templ_7745c5c3_Var60 string
1209+ templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Key)
1210+ if templ_7745c5c3_Err != nil {
1211+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 224, Col: 19}
1212+ }
1213+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var60)
1214+ if templ_7745c5c3_Err != nil {
1215+ return templ_7745c5c3_Err
1216+ }
1217+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "\"")
1132 if templ_7745c5c3_Err != nil {1218 if templ_7745c5c3_Err != nil {
1133 return templ_7745c5c3_Err1219 return templ_7745c5c3_Err
1134 }1220 }
1135 if f.Open {1221 if f.Open {
1136- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, " open")1222+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, " open")
1137 if templ_7745c5c3_Err != nil {1223 if templ_7745c5c3_Err != nil {
1138 return templ_7745c5c3_Err1224 return templ_7745c5c3_Err
1139 }1225 }
1140 }1226 }
1141- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "><summary><span class=\"st\">")1227+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "><summary><span class=\"st\">")
1142 if templ_7745c5c3_Err != nil {1228 if templ_7745c5c3_Err != nil {
1143 return templ_7745c5c3_Err1229 return templ_7745c5c3_Err
1144 }1230 }
1145- var templ_7745c5c3_Var57 string1231+ var templ_7745c5c3_Var61 string
1146- templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)1232+ templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(f.Status)
1147 if templ_7745c5c3_Err != nil {1233 if templ_7745c5c3_Err != nil {
1148- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 30}1234+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 30}
1149 }1235 }
1150- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57))1236+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))
1151 if templ_7745c5c3_Err != nil {1237 if templ_7745c5c3_Err != nil {
1152 return templ_7745c5c3_Err1238 return templ_7745c5c3_Err
1153 }1239 }
1154- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "</span>")1240+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "</span>")
1155 if templ_7745c5c3_Err != nil {1241 if templ_7745c5c3_Err != nil {
1156 return templ_7745c5c3_Err1242 return templ_7745c5c3_Err
1157 }1243 }
1158- var templ_7745c5c3_Var58 string1244+ var templ_7745c5c3_Var62 string
1159- templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1245+ templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1160 if templ_7745c5c3_Err != nil {1246 if templ_7745c5c3_Err != nil {
1161- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 44}1247+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 44}
1162 }1248 }
1163- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58))1249+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))
1164 if templ_7745c5c3_Err != nil {1250 if templ_7745c5c3_Err != nil {
1165 return templ_7745c5c3_Err1251 return templ_7745c5c3_Err
1166 }1252 }
1167- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 103, "<span class=\"p\">")1253+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<span class=\"p\">")
1168 if templ_7745c5c3_Err != nil {1254 if templ_7745c5c3_Err != nil {
1169 return templ_7745c5c3_Err1255 return templ_7745c5c3_Err
1170 }1256 }
1171- var templ_7745c5c3_Var59 string1257+ var templ_7745c5c3_Var63 string
1172- templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(f.Path)1258+ templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(f.Path)
1173 if templ_7745c5c3_Err != nil {1259 if templ_7745c5c3_Err != nil {
1174- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 70}1260+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 70}
1175 }1261 }
1176- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59))1262+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63))
1177 if templ_7745c5c3_Err != nil {1263 if templ_7745c5c3_Err != nil {
1178 return templ_7745c5c3_Err1264 return templ_7745c5c3_Err
1179 }1265 }
1180- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "</span>")1266+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "</span>")
1181 if templ_7745c5c3_Err != nil {1267 if templ_7745c5c3_Err != nil {
1182 return templ_7745c5c3_Err1268 return templ_7745c5c3_Err
1183 }1269 }
1184- var templ_7745c5c3_Var60 string1270+ var templ_7745c5c3_Var64 string
1185- templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1271+ templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1186 if templ_7745c5c3_Err != nil {1272 if templ_7745c5c3_Err != nil {
1187- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 84}1273+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 84}
1188 }1274 }
1189- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var60))1275+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))
1190 if templ_7745c5c3_Err != nil {1276 if templ_7745c5c3_Err != nil {
1191 return templ_7745c5c3_Err1277 return templ_7745c5c3_Err
1192 }1278 }
1193- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 105, "<span class=\"plus\">+")1279+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "<span class=\"plus\">+")
1194 if templ_7745c5c3_Err != nil {1280 if templ_7745c5c3_Err != nil {
1195 return templ_7745c5c3_Err1281 return templ_7745c5c3_Err
1196 }1282 }
1197- var templ_7745c5c3_Var61 string1283+ var templ_7745c5c3_Var65 string
1198- templ_7745c5c3_Var61, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))1284+ templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Add))
1199 if templ_7745c5c3_Err != nil {1285 if templ_7745c5c3_Err != nil {
1200- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 119}1286+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 119}
1201 }1287 }
1202- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var61))1288+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))
1203 if templ_7745c5c3_Err != nil {1289 if templ_7745c5c3_Err != nil {
1204 return templ_7745c5c3_Err1290 return templ_7745c5c3_Err
1205 }1291 }
1206- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "</span>")1292+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "</span>")
1207 if templ_7745c5c3_Err != nil {1293 if templ_7745c5c3_Err != nil {
1208 return templ_7745c5c3_Err1294 return templ_7745c5c3_Err
1209 }1295 }
1210- var templ_7745c5c3_Var62 string1296+ var templ_7745c5c3_Var66 string
1211- templ_7745c5c3_Var62, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1297+ templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1212 if templ_7745c5c3_Err != nil {1298 if templ_7745c5c3_Err != nil {
1213- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 133}1299+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 133}
1214 }1300 }
1215- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var62))1301+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66))
1216 if templ_7745c5c3_Err != nil {1302 if templ_7745c5c3_Err != nil {
1217 return templ_7745c5c3_Err1303 return templ_7745c5c3_Err
1218 }1304 }
1219- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 107, "<span class=\"minus\">-")1305+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<span class=\"minus\">-")
1220 if templ_7745c5c3_Err != nil {1306 if templ_7745c5c3_Err != nil {
1221 return templ_7745c5c3_Err1307 return templ_7745c5c3_Err
1222 }1308 }
1223- var templ_7745c5c3_Var63 string1309+ var templ_7745c5c3_Var67 string
1224- templ_7745c5c3_Var63, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))1310+ templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(itoa(f.Del))
1225 if templ_7745c5c3_Err != nil {1311 if templ_7745c5c3_Err != nil {
1226- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 212, Col: 169}1312+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 230, Col: 169}
1227 }1313 }
1228- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var63))1314+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67))
1229 if templ_7745c5c3_Err != nil {1315 if templ_7745c5c3_Err != nil {
1230 return templ_7745c5c3_Err1316 return templ_7745c5c3_Err
1231 }1317 }
1232- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "</span> ")1318+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "</span> ")
1233 if templ_7745c5c3_Err != nil {1319 if templ_7745c5c3_Err != nil {
1234 return templ_7745c5c3_Err1320 return templ_7745c5c3_Err
1235 }1321 }
1236 if f.Note != "" {1322 if f.Note != "" {
1237- var templ_7745c5c3_Var64 string1323+ var templ_7745c5c3_Var68 string
1238- templ_7745c5c3_Var64, templ_7745c5c3_Err = templ.JoinStringErrs(" ")1324+ templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
1239 if templ_7745c5c3_Err != nil {1325 if templ_7745c5c3_Err != nil {
1240- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 214, Col: 9}1326+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 232, Col: 9}
1241 }1327 }
1242- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var64))1328+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
1243 if templ_7745c5c3_Err != nil {1329 if templ_7745c5c3_Err != nil {
1244 return templ_7745c5c3_Err1330 return templ_7745c5c3_Err
1245 }1331 }
1246- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 109, "<span class=\"note\">")1332+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "<span class=\"note\">")
1247 if templ_7745c5c3_Err != nil {1333 if templ_7745c5c3_Err != nil {
1248 return templ_7745c5c3_Err1334 return templ_7745c5c3_Err
1249 }1335 }
1250- var templ_7745c5c3_Var65 string1336+ var templ_7745c5c3_Var69 string
1251- templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)1337+ templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
1252 if templ_7745c5c3_Err != nil {1338 if templ_7745c5c3_Err != nil {
1253- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 214, Col: 38}1339+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 232, Col: 38}
1254 }1340 }
1255- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65))1341+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
1256 if templ_7745c5c3_Err != nil {1342 if templ_7745c5c3_Err != nil {
1257 return templ_7745c5c3_Err1343 return templ_7745c5c3_Err
1258 }1344 }
1259- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "</span>")1345+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "</span>")
1260 if templ_7745c5c3_Err != nil {1346 if templ_7745c5c3_Err != nil {
1261 return templ_7745c5c3_Err1347 return templ_7745c5c3_Err
1262 }1348 }
1263 }1349 }
1264- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 111, "</summary> ")1350+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "</summary> ")
1265 if templ_7745c5c3_Err != nil {1351 if templ_7745c5c3_Err != nil {
1266 return templ_7745c5c3_Err1352 return templ_7745c5c3_Err
1267 }1353 }
1268 if f.Lazy {1354 if f.Lazy {
1269- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, " ")1355+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, " ")
1270 if templ_7745c5c3_Err != nil {1356 if templ_7745c5c3_Err != nil {
1271 return templ_7745c5c3_Err1357 return templ_7745c5c3_Err
1272 }1358 }
1273- var templ_7745c5c3_Var66 = []any{"dlazy", "dlazy-" + itoa(f.Height)}1359+ var templ_7745c5c3_Var70 = []any{"dlazy", "dlazy-" + itoa(f.Height)}
1274- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var66...)1360+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var70...)
1275 if templ_7745c5c3_Err != nil {1361 if templ_7745c5c3_Err != nil {
1276 return templ_7745c5c3_Err1362 return templ_7745c5c3_Err
1277 }1363 }
1278- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 113, "<div class=\"")1364+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "<div class=\"")
1279 if templ_7745c5c3_Err != nil {1365 if templ_7745c5c3_Err != nil {
1280 return templ_7745c5c3_Err1366 return templ_7745c5c3_Err
1281 }1367 }
1282- var templ_7745c5c3_Var67 string1368+ var templ_7745c5c3_Var71 string
1283- templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var66).String())1369+ templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var70).String())
1284 if templ_7745c5c3_Err != nil {1370 if templ_7745c5c3_Err != nil {
1285 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}1371 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
1286 }1372 }
1287- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var67)1373+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)
1288 if templ_7745c5c3_Err != nil {1374 if templ_7745c5c3_Err != nil {
1289 return templ_7745c5c3_Err1375 return templ_7745c5c3_Err
1290 }1376 }
1291- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "\" data-src=\"")1377+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, "\" data-src=\"")
1292 if templ_7745c5c3_Err != nil {1378 if templ_7745c5c3_Err != nil {
1293 return templ_7745c5c3_Err1379 return templ_7745c5c3_Err
1294 }1380 }
1295- var templ_7745c5c3_Var68 string1381+ var templ_7745c5c3_Var72 string
1296- templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Src)1382+ templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Src)
1297 if templ_7745c5c3_Err != nil {1383 if templ_7745c5c3_Err != nil {
1298- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 221, Col: 69}1384+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 239, Col: 69}
1299 }1385 }
1300- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var68)1386+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var72)
1301 if templ_7745c5c3_Err != nil {1387 if templ_7745c5c3_Err != nil {
1302 return templ_7745c5c3_Err1388 return templ_7745c5c3_Err
1303 }1389 }
1304- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 115, "\" data-notes=\"")1390+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "\" data-notes=\"")
1305 if templ_7745c5c3_Err != nil {1391 if templ_7745c5c3_Err != nil {
1306 return templ_7745c5c3_Err1392 return templ_7745c5c3_Err
1307 }1393 }
1308- var templ_7745c5c3_Var69 string1394+ var templ_7745c5c3_Var73 string
1309- templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Comments)1395+ templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Comments)
1310 if templ_7745c5c3_Err != nil {1396 if templ_7745c5c3_Err != nil {
1311- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 221, Col: 95}1397+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 239, Col: 95}
1312 }1398 }
1313- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var69)1399+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var73)
1314 if templ_7745c5c3_Err != nil {1400 if templ_7745c5c3_Err != nil {
1315 return templ_7745c5c3_Err1401 return templ_7745c5c3_Err
1316 }1402 }
1317- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "\"><a href=\"")1403+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "\"><a href=\"")
1318 if templ_7745c5c3_Err != nil {1404 if templ_7745c5c3_Err != nil {
1319 return templ_7745c5c3_Err1405 return templ_7745c5c3_Err
1320 }1406 }
1321- var templ_7745c5c3_Var70 templ.SafeURL1407+ var templ_7745c5c3_Var74 templ.SafeURL
1322- templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?from=" + itoa(f.From) + "#" + f.ID))1408+ templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?from=" + itoa(f.From) + "#" + f.ID))
1323 if templ_7745c5c3_Err != nil {1409 if templ_7745c5c3_Err != nil {
1324- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 222, Col: 65}1410+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 240, Col: 65}
1325 }1411 }
1326- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))1412+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74))
1327 if templ_7745c5c3_Err != nil {1413 if templ_7745c5c3_Err != nil {
1328 return templ_7745c5c3_Err1414 return templ_7745c5c3_Err
1329 }1415 }
1330- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 117, "\">show this file</a></div>")1416+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "\">show this file</a></div>")
1331 if templ_7745c5c3_Err != nil {1417 if templ_7745c5c3_Err != nil {
1332 return templ_7745c5c3_Err1418 return templ_7745c5c3_Err
1333 }1419 }
1334 } else if len(f.Hunks) > 0 {1420 } else if len(f.Hunks) > 0 {
1335- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "<div class=\"dscroll\">")1421+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "<div class=\"dscroll\">")
1336 if templ_7745c5c3_Err != nil {1422 if templ_7745c5c3_Err != nil {
1337 return templ_7745c5c3_Err1423 return templ_7745c5c3_Err
1338 }1424 }
1339 if p.ShowUnified {1425 if p.ShowUnified {
1340- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "<table class=\"dt uni\" aria-label=\"")1426+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 125, "<table class=\"dt uni\" aria-label=\"")
1341 if templ_7745c5c3_Err != nil {1427 if templ_7745c5c3_Err != nil {
1342 return templ_7745c5c3_Err1428 return templ_7745c5c3_Err
1343 }1429 }
1344- var templ_7745c5c3_Var71 string1430+ var templ_7745c5c3_Var75 string
1345- templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", unified")1431+ templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", unified")
1346 if templ_7745c5c3_Err != nil {1432 if templ_7745c5c3_Err != nil {
1347- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 227, Col: 60}1433+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 245, Col: 60}
1348 }1434 }
1349- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var71)1435+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var75)
1350 if templ_7745c5c3_Err != nil {1436 if templ_7745c5c3_Err != nil {
1351 return templ_7745c5c3_Err1437 return templ_7745c5c3_Err
1352 }1438 }
1353- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, "\">")1439+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 126, "\">")
1354 if templ_7745c5c3_Err != nil {1440 if templ_7745c5c3_Err != nil {
1355 return templ_7745c5c3_Err1441 return templ_7745c5c3_Err
1356 }1442 }
1357 for _, h := range f.Hunks {1443 for _, h := range f.Hunks {
1358- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "<tbody>")1444+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, "<tbody>")
1359 if templ_7745c5c3_Err != nil {1445 if templ_7745c5c3_Err != nil {
1360 return templ_7745c5c3_Err1446 return templ_7745c5c3_Err
1361 }1447 }
@@ -1365,43 +1451,43 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1365 return templ_7745c5c3_Err1451 return templ_7745c5c3_Err
1366 }1452 }
1367 }1453 }
1368- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "<tr class=\"hunk\"><td colspan=\"4\">")1454+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "<tr class=\"hunk\"><td colspan=\"4\">")
1369 if templ_7745c5c3_Err != nil {1455 if templ_7745c5c3_Err != nil {
1370 return templ_7745c5c3_Err1456 return templ_7745c5c3_Err
1371 }1457 }
1372- var templ_7745c5c3_Var72 string1458+ var templ_7745c5c3_Var76 string
1373- templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)1459+ templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
1374 if templ_7745c5c3_Err != nil {1460 if templ_7745c5c3_Err != nil {
1375- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 233, Col: 51}1461+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 251, Col: 51}
1376 }1462 }
1377- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72))1463+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76))
1378 if templ_7745c5c3_Err != nil {1464 if templ_7745c5c3_Err != nil {
1379 return templ_7745c5c3_Err1465 return templ_7745c5c3_Err
1380 }1466 }
1381- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "</td></tr>")1467+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "</td></tr>")
1382 if templ_7745c5c3_Err != nil {1468 if templ_7745c5c3_Err != nil {
1383 return templ_7745c5c3_Err1469 return templ_7745c5c3_Err
1384 }1470 }
1385 for _, ln := range h.Lines {1471 for _, ln := range h.Lines {
1386- var templ_7745c5c3_Var73 = []any{ln.Kind, templ.KV("sel", ln.Selected)}1472+ var templ_7745c5c3_Var77 = []any{ln.Kind, templ.KV("sel", ln.Selected)}
1387- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var73...)1473+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var77...)
1388 if templ_7745c5c3_Err != nil {1474 if templ_7745c5c3_Err != nil {
1389 return templ_7745c5c3_Err1475 return templ_7745c5c3_Err
1390 }1476 }
1391- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "<tr class=\"")1477+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "<tr class=\"")
1392 if templ_7745c5c3_Err != nil {1478 if templ_7745c5c3_Err != nil {
1393 return templ_7745c5c3_Err1479 return templ_7745c5c3_Err
1394 }1480 }
1395- var templ_7745c5c3_Var74 string1481+ var templ_7745c5c3_Var78 string
1396- templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var73).String())1482+ templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var77).String())
1397 if templ_7745c5c3_Err != nil {1483 if templ_7745c5c3_Err != nil {
1398 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}1484 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
1399 }1485 }
1400- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var74)1486+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var78)
1401 if templ_7745c5c3_Err != nil {1487 if templ_7745c5c3_Err != nil {
1402 return templ_7745c5c3_Err1488 return templ_7745c5c3_Err
1403 }1489 }
1404- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 125, "\"><td class=\"ln\">")1490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 131, "\"><td class=\"ln\">")
1405 if templ_7745c5c3_Err != nil {1491 if templ_7745c5c3_Err != nil {
1406 return templ_7745c5c3_Err1492 return templ_7745c5c3_Err
1407 }1493 }
@@ -1409,7 +1495,7 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1409 if templ_7745c5c3_Err != nil {1495 if templ_7745c5c3_Err != nil {
1410 return templ_7745c5c3_Err1496 return templ_7745c5c3_Err
1411 }1497 }
1412- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 126, "</td><td class=\"ln\">")1498+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 132, "</td><td class=\"ln\">")
1413 if templ_7745c5c3_Err != nil {1499 if templ_7745c5c3_Err != nil {
1414 return templ_7745c5c3_Err1500 return templ_7745c5c3_Err
1415 }1501 }
@@ -1417,20 +1503,20 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1417 if templ_7745c5c3_Err != nil {1503 if templ_7745c5c3_Err != nil {
1418 return templ_7745c5c3_Err1504 return templ_7745c5c3_Err
1419 }1505 }
1420- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, "</td><td class=\"m\">")1506+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 133, "</td><td class=\"m\">")
1421 if templ_7745c5c3_Err != nil {1507 if templ_7745c5c3_Err != nil {
1422 return templ_7745c5c3_Err1508 return templ_7745c5c3_Err
1423 }1509 }
1424- var templ_7745c5c3_Var75 string1510+ var templ_7745c5c3_Var79 string
1425- templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)1511+ templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
1426 if templ_7745c5c3_Err != nil {1512 if templ_7745c5c3_Err != nil {
1427- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 238, Col: 33}1513+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 256, Col: 33}
1428 }1514 }
1429- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75))1515+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79))
1430 if templ_7745c5c3_Err != nil {1516 if templ_7745c5c3_Err != nil {
1431 return templ_7745c5c3_Err1517 return templ_7745c5c3_Err
1432 }1518 }
1433- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "</td><td class=\"tx chroma\">")1519+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 134, "</td><td class=\"tx chroma\">")
1434 if templ_7745c5c3_Err != nil {1520 if templ_7745c5c3_Err != nil {
1435 return templ_7745c5c3_Err1521 return templ_7745c5c3_Err
1436 }1522 }
@@ -1438,12 +1524,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1438 if templ_7745c5c3_Err != nil {1524 if templ_7745c5c3_Err != nil {
1439 return templ_7745c5c3_Err1525 return templ_7745c5c3_Err
1440 }1526 }
1441- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "</td></tr>")1527+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 135, "</td></tr>")
1442 if templ_7745c5c3_Err != nil {1528 if templ_7745c5c3_Err != nil {
1443 return templ_7745c5c3_Err1529 return templ_7745c5c3_Err
1444 }1530 }
1445 if len(ln.Notes) > 0 || ln.Form != nil {1531 if len(ln.Notes) > 0 || ln.Form != nil {
1446- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "<tr class=\"fnote\"><td colspan=\"3\"></td><td>")1532+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 136, "<tr class=\"fnote\"><td colspan=\"3\"></td><td>")
1447 if templ_7745c5c3_Err != nil {1533 if templ_7745c5c3_Err != nil {
1448 return templ_7745c5c3_Err1534 return templ_7745c5c3_Err
1449 }1535 }
@@ -1451,19 +1537,19 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1451 if templ_7745c5c3_Err != nil {1537 if templ_7745c5c3_Err != nil {
1452 return templ_7745c5c3_Err1538 return templ_7745c5c3_Err
1453 }1539 }
1454- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 131, "</td></tr>")1540+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 137, "</td></tr>")
1455 if templ_7745c5c3_Err != nil {1541 if templ_7745c5c3_Err != nil {
1456 return templ_7745c5c3_Err1542 return templ_7745c5c3_Err
1457 }1543 }
1458 }1544 }
1459 }1545 }
1460- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 132, "</tbody> ")1546+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 138, "</tbody> ")
1461 if templ_7745c5c3_Err != nil {1547 if templ_7745c5c3_Err != nil {
1462 return templ_7745c5c3_Err1548 return templ_7745c5c3_Err
1463 }1549 }
1464 }1550 }
1465 if f.Tail != nil {1551 if f.Tail != nil {
1466- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 133, "<tbody>")1552+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 139, "<tbody>")
1467 if templ_7745c5c3_Err != nil {1553 if templ_7745c5c3_Err != nil {
1468 return templ_7745c5c3_Err1554 return templ_7745c5c3_Err
1469 }1555 }
@@ -1471,36 +1557,36 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1471 if templ_7745c5c3_Err != nil {1557 if templ_7745c5c3_Err != nil {
1472 return templ_7745c5c3_Err1558 return templ_7745c5c3_Err
1473 }1559 }
1474- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 134, "</tbody>")1560+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 140, "</tbody>")
1475 if templ_7745c5c3_Err != nil {1561 if templ_7745c5c3_Err != nil {
1476 return templ_7745c5c3_Err1562 return templ_7745c5c3_Err
1477 }1563 }
1478 }1564 }
1479- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 135, "</table>")1565+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 141, "</table>")
1480 if templ_7745c5c3_Err != nil {1566 if templ_7745c5c3_Err != nil {
1481 return templ_7745c5c3_Err1567 return templ_7745c5c3_Err
1482 }1568 }
1483 }1569 }
1484 if p.ShowSplit {1570 if p.ShowSplit {
1485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 136, "<table class=\"dt spl\" aria-label=\"")1571+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 142, "<table class=\"dt spl\" aria-label=\"")
1486 if templ_7745c5c3_Err != nil {1572 if templ_7745c5c3_Err != nil {
1487 return templ_7745c5c3_Err1573 return templ_7745c5c3_Err
1488 }1574 }
1489- var templ_7745c5c3_Var76 string1575+ var templ_7745c5c3_Var80 string
1490- templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", split")1576+ templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.ResolveAttributeValue(f.Path + ", split")
1491 if templ_7745c5c3_Err != nil {1577 if templ_7745c5c3_Err != nil {
1492- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 258, Col: 58}1578+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 276, Col: 58}
1493 }1579 }
1494- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var76)1580+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var80)
1495 if templ_7745c5c3_Err != nil {1581 if templ_7745c5c3_Err != nil {
1496 return templ_7745c5c3_Err1582 return templ_7745c5c3_Err
1497 }1583 }
1498- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 137, "\"><colgroup><col class=\"c-ln\"><col class=\"c-m\"><col><col class=\"c-ln\"><col class=\"c-m\"><col></colgroup> ")1584+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 143, "\"><colgroup><col class=\"c-ln\"><col class=\"c-m\"><col><col class=\"c-ln\"><col class=\"c-m\"><col></colgroup> ")
1499 if templ_7745c5c3_Err != nil {1585 if templ_7745c5c3_Err != nil {
1500 return templ_7745c5c3_Err1586 return templ_7745c5c3_Err
1501 }1587 }
1502 for _, h := range f.Hunks {1588 for _, h := range f.Hunks {
1503- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 138, "<tbody>")1589+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 144, "<tbody>")
1504 if templ_7745c5c3_Err != nil {1590 if templ_7745c5c3_Err != nil {
1505 return templ_7745c5c3_Err1591 return templ_7745c5c3_Err
1506 }1592 }
@@ -1510,25 +1596,25 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1510 return templ_7745c5c3_Err1596 return templ_7745c5c3_Err
1511 }1597 }
1512 }1598 }
1513- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 139, "<tr class=\"hunk\"><td colspan=\"6\">")1599+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 145, "<tr class=\"hunk\"><td colspan=\"6\">")
1514 if templ_7745c5c3_Err != nil {1600 if templ_7745c5c3_Err != nil {
1515 return templ_7745c5c3_Err1601 return templ_7745c5c3_Err
1516 }1602 }
1517- var templ_7745c5c3_Var77 string1603+ var templ_7745c5c3_Var81 string
1518- templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)1604+ templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinStringErrs(h.Header)
1519 if templ_7745c5c3_Err != nil {1605 if templ_7745c5c3_Err != nil {
1520- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 265, Col: 51}1606+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 283, Col: 51}
1521 }1607 }
1522- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77))1608+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81))
1523 if templ_7745c5c3_Err != nil {1609 if templ_7745c5c3_Err != nil {
1524 return templ_7745c5c3_Err1610 return templ_7745c5c3_Err
1525 }1611 }
1526- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 140, "</td></tr>")1612+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 146, "</td></tr>")
1527 if templ_7745c5c3_Err != nil {1613 if templ_7745c5c3_Err != nil {
1528 return templ_7745c5c3_Err1614 return templ_7745c5c3_Err
1529 }1615 }
1530 for _, row := range h.Split {1616 for _, row := range h.Split {
1531- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 141, "<tr>")1617+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 147, "<tr>")
1532 if templ_7745c5c3_Err != nil {1618 if templ_7745c5c3_Err != nil {
1533 return templ_7745c5c3_Err1619 return templ_7745c5c3_Err
1534 }1620 }
@@ -1540,12 +1626,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1540 if templ_7745c5c3_Err != nil {1626 if templ_7745c5c3_Err != nil {
1541 return templ_7745c5c3_Err1627 return templ_7745c5c3_Err
1542 }1628 }
1543- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 142, "</tr>")1629+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 148, "</tr>")
1544 if templ_7745c5c3_Err != nil {1630 if templ_7745c5c3_Err != nil {
1545 return templ_7745c5c3_Err1631 return templ_7745c5c3_Err
1546 }1632 }
1547 if notes, form := row.Notes(), row.Form(); len(notes) > 0 || form != nil {1633 if notes, form := row.Notes(), row.Form(); len(notes) > 0 || form != nil {
1548- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 143, "<tr class=\"fnote\"><td colspan=\"6\">")1634+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 149, "<tr class=\"fnote\"><td colspan=\"6\">")
1549 if templ_7745c5c3_Err != nil {1635 if templ_7745c5c3_Err != nil {
1550 return templ_7745c5c3_Err1636 return templ_7745c5c3_Err
1551 }1637 }
@@ -1553,19 +1639,19 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1553 if templ_7745c5c3_Err != nil {1639 if templ_7745c5c3_Err != nil {
1554 return templ_7745c5c3_Err1640 return templ_7745c5c3_Err
1555 }1641 }
1556- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 144, "</td></tr>")1642+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 150, "</td></tr>")
1557 if templ_7745c5c3_Err != nil {1643 if templ_7745c5c3_Err != nil {
1558 return templ_7745c5c3_Err1644 return templ_7745c5c3_Err
1559 }1645 }
1560 }1646 }
1561 }1647 }
1562- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 145, "</tbody> ")1648+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 151, "</tbody> ")
1563 if templ_7745c5c3_Err != nil {1649 if templ_7745c5c3_Err != nil {
1564 return templ_7745c5c3_Err1650 return templ_7745c5c3_Err
1565 }1651 }
1566 }1652 }
1567 if f.Tail != nil {1653 if f.Tail != nil {
1568- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 146, "<tbody>")1654+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 152, "<tbody>")
1569 if templ_7745c5c3_Err != nil {1655 if templ_7745c5c3_Err != nil {
1570 return templ_7745c5c3_Err1656 return templ_7745c5c3_Err
1571 }1657 }
@@ -1573,48 +1659,48 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1573 if templ_7745c5c3_Err != nil {1659 if templ_7745c5c3_Err != nil {
1574 return templ_7745c5c3_Err1660 return templ_7745c5c3_Err
1575 }1661 }
1576- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 147, "</tbody>")1662+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 153, "</tbody>")
1577 if templ_7745c5c3_Err != nil {1663 if templ_7745c5c3_Err != nil {
1578 return templ_7745c5c3_Err1664 return templ_7745c5c3_Err
1579 }1665 }
1580 }1666 }
1581- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 148, "</table>")1667+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 154, "</table>")
1582 if templ_7745c5c3_Err != nil {1668 if templ_7745c5c3_Err != nil {
1583 return templ_7745c5c3_Err1669 return templ_7745c5c3_Err
1584 }1670 }
1585 }1671 }
1586- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 149, "</div>")1672+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 155, "</div>")
1587 if templ_7745c5c3_Err != nil {1673 if templ_7745c5c3_Err != nil {
1588 return templ_7745c5c3_Err1674 return templ_7745c5c3_Err
1589 }1675 }
1590 } else {1676 } else {
1591- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 150, "<p class=\"note pad\">")1677+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 156, "<p class=\"note pad\">")
1592 if templ_7745c5c3_Err != nil {1678 if templ_7745c5c3_Err != nil {
1593 return templ_7745c5c3_Err1679 return templ_7745c5c3_Err
1594 }1680 }
1595 if f.Note != "" {1681 if f.Note != "" {
1596- var templ_7745c5c3_Var78 string1682+ var templ_7745c5c3_Var82 string
1597- templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)1683+ templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.JoinStringErrs(f.Note)
1598 if templ_7745c5c3_Err != nil {1684 if templ_7745c5c3_Err != nil {
1599- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 290, Col: 13}1685+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 308, Col: 13}
1600 }1686 }
1601- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78))1687+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var82))
1602 if templ_7745c5c3_Err != nil {1688 if templ_7745c5c3_Err != nil {
1603 return templ_7745c5c3_Err1689 return templ_7745c5c3_Err
1604 }1690 }
1605 } else {1691 } else {
1606- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 151, "no textual change.")1692+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 157, "no textual change.")
1607 if templ_7745c5c3_Err != nil {1693 if templ_7745c5c3_Err != nil {
1608 return templ_7745c5c3_Err1694 return templ_7745c5c3_Err
1609 }1695 }
1610 }1696 }
1611- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 152, "</p>")1697+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 158, "</p>")
1612 if templ_7745c5c3_Err != nil {1698 if templ_7745c5c3_Err != nil {
1613 return templ_7745c5c3_Err1699 return templ_7745c5c3_Err
1614 }1700 }
1615 }1701 }
1616 if len(f.Loose) > 0 {1702 if len(f.Loose) > 0 {
1617- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 153, "<div class=\"dloose\">")1703+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 159, "<div class=\"dloose\">")
1618 if templ_7745c5c3_Err != nil {1704 if templ_7745c5c3_Err != nil {
1619 return templ_7745c5c3_Err1705 return templ_7745c5c3_Err
1620 }1706 }
@@ -1624,12 +1710,12 @@ func DiffFileView(f DiffFile, p DiffView) templ.Component {
1624 return templ_7745c5c3_Err1710 return templ_7745c5c3_Err
1625 }1711 }
1626 }1712 }
1627- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 154, "</div>")1713+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 160, "</div>")
1628 if templ_7745c5c3_Err != nil {1714 if templ_7745c5c3_Err != nil {
1629 return templ_7745c5c3_Err1715 return templ_7745c5c3_Err
1630 }1716 }
1631 }1717 }
1632- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 155, "</details>")1718+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 161, "</details>")
1633 if templ_7745c5c3_Err != nil {1719 if templ_7745c5c3_Err != nil {
1634 return templ_7745c5c3_Err1720 return templ_7745c5c3_Err
1635 }1721 }
@@ -1655,9 +1741,9 @@ func MRFiles(p MRFilesPage) templ.Component {
1655 }()1741 }()
1656 }1742 }
1657 ctx = templ.InitializeContext(ctx)1743 ctx = templ.InitializeContext(ctx)
1658- templ_7745c5c3_Var79 := templ.GetChildren(ctx)1744+ templ_7745c5c3_Var83 := templ.GetChildren(ctx)
1659- if templ_7745c5c3_Var79 == nil {1745+ if templ_7745c5c3_Var83 == nil {
1660- templ_7745c5c3_Var79 = templ.NopComponent1746+ templ_7745c5c3_Var83 = templ.NopComponent
1661 }1747 }
1662 ctx = templ.ClearChildren(ctx)1748 ctx = templ.ClearChildren(ctx)
1663 for _, f := range p.Files {1749 for _, f := range p.Files {
@@ -1688,12 +1774,12 @@ func MRFilesMoved() templ.Component {
1688 }()1774 }()
1689 }1775 }
1690 ctx = templ.InitializeContext(ctx)1776 ctx = templ.InitializeContext(ctx)
1691- templ_7745c5c3_Var80 := templ.GetChildren(ctx)1777+ templ_7745c5c3_Var84 := templ.GetChildren(ctx)
1692- if templ_7745c5c3_Var80 == nil {1778+ if templ_7745c5c3_Var84 == nil {
1693- templ_7745c5c3_Var80 = templ.NopComponent1779+ templ_7745c5c3_Var84 = templ.NopComponent
1694 }1780 }
1695 ctx = templ.ClearChildren(ctx)1781 ctx = templ.ClearChildren(ctx)
1696- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 156, "<p class=\"notice\" data-moved>this merge request changed since the page was loaded — <a href=\"\">reload</a></p>")1782+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 162, "<p class=\"notice\" data-moved>this merge request changed since the page was loaded — <a href=\"\">reload</a></p>")
1697 if templ_7745c5c3_Err != nil {1783 if templ_7745c5c3_Err != nil {
1698 return templ_7745c5c3_Err1784 return templ_7745c5c3_Err
1699 }1785 }
@@ -1720,64 +1806,64 @@ func gapRow(g DiffGap, cols int) templ.Component {
1720 }()1806 }()
1721 }1807 }
1722 ctx = templ.InitializeContext(ctx)1808 ctx = templ.InitializeContext(ctx)
1723- templ_7745c5c3_Var81 := templ.GetChildren(ctx)1809+ templ_7745c5c3_Var85 := templ.GetChildren(ctx)
1724- if templ_7745c5c3_Var81 == nil {1810+ if templ_7745c5c3_Var85 == nil {
1725- templ_7745c5c3_Var81 = templ.NopComponent1811+ templ_7745c5c3_Var85 = templ.NopComponent
1726 }1812 }
1727 ctx = templ.ClearChildren(ctx)1813 ctx = templ.ClearChildren(ctx)
1728- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 157, "<tr class=\"gap\" data-js data-gap=\"")1814+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 163, "<tr class=\"gap\" data-js data-gap=\"")
1729 if templ_7745c5c3_Err != nil {1815 if templ_7745c5c3_Err != nil {
1730 return templ_7745c5c3_Err1816 return templ_7745c5c3_Err
1731 }1817 }
1732- var templ_7745c5c3_Var82 string1818+ var templ_7745c5c3_Var86 string
1733- templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Key)1819+ templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Key)
1734 if templ_7745c5c3_Err != nil {1820 if templ_7745c5c3_Err != nil {
1735- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 324, Col: 41}1821+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 342, Col: 41}
1736 }1822 }
1737- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var82)1823+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var86)
1738 if templ_7745c5c3_Err != nil {1824 if templ_7745c5c3_Err != nil {
1739 return templ_7745c5c3_Err1825 return templ_7745c5c3_Err
1740 }1826 }
1741- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 158, "\"><td colspan=\"")1827+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 164, "\"><td colspan=\"")
1742 if templ_7745c5c3_Err != nil {1828 if templ_7745c5c3_Err != nil {
1743 return templ_7745c5c3_Err1829 return templ_7745c5c3_Err
1744 }1830 }
1745- var templ_7745c5c3_Var83 string1831+ var templ_7745c5c3_Var87 string
1746- templ_7745c5c3_Var83, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(cols))1832+ templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.ResolveAttributeValue(itoa(cols))
1747 if templ_7745c5c3_Err != nil {1833 if templ_7745c5c3_Err != nil {
1748- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 325, Col: 26}1834+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 343, Col: 26}
1749 }1835 }
1750- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var83)1836+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var87)
1751 if templ_7745c5c3_Err != nil {1837 if templ_7745c5c3_Err != nil {
1752 return templ_7745c5c3_Err1838 return templ_7745c5c3_Err
1753 }1839 }
1754- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 159, "\"><button type=\"button\" data-src=\"")1840+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 165, "\"><button type=\"button\" data-src=\"")
1755 if templ_7745c5c3_Err != nil {1841 if templ_7745c5c3_Err != nil {
1756 return templ_7745c5c3_Err1842 return templ_7745c5c3_Err
1757 }1843 }
1758- var templ_7745c5c3_Var84 string1844+ var templ_7745c5c3_Var88 string
1759- templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Src)1845+ templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.ResolveAttributeValue(g.Src)
1760 if templ_7745c5c3_Err != nil {1846 if templ_7745c5c3_Err != nil {
1761- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 326, Col: 41}1847+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 344, Col: 41}
1762 }1848 }
1763- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var84)1849+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var88)
1764 if templ_7745c5c3_Err != nil {1850 if templ_7745c5c3_Err != nil {
1765 return templ_7745c5c3_Err1851 return templ_7745c5c3_Err
1766 }1852 }
1767- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 160, "\"><span aria-hidden=\"true\">⋯</span> ")1853+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 166, "\"><span aria-hidden=\"true\">⋯</span> ")
1768 if templ_7745c5c3_Err != nil {1854 if templ_7745c5c3_Err != nil {
1769 return templ_7745c5c3_Err1855 return templ_7745c5c3_Err
1770 }1856 }
1771- var templ_7745c5c3_Var85 string1857+ var templ_7745c5c3_Var89 string
1772- templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(g.Label())1858+ templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(g.Label())
1773 if templ_7745c5c3_Err != nil {1859 if templ_7745c5c3_Err != nil {
1774- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 327, Col: 51}1860+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 345, Col: 51}
1775 }1861 }
1776- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85))1862+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
1777 if templ_7745c5c3_Err != nil {1863 if templ_7745c5c3_Err != nil {
1778 return templ_7745c5c3_Err1864 return templ_7745c5c3_Err
1779 }1865 }
1780- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 161, "</button></td></tr>")1866+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 167, "</button></td></tr>")
1781 if templ_7745c5c3_Err != nil {1867 if templ_7745c5c3_Err != nil {
1782 return templ_7745c5c3_Err1868 return templ_7745c5c3_Err
1783 }1869 }
@@ -1803,56 +1889,56 @@ func DiffContext(c ContextRows) templ.Component {
1803 }()1889 }()
1804 }1890 }
1805 ctx = templ.InitializeContext(ctx)1891 ctx = templ.InitializeContext(ctx)
1806- templ_7745c5c3_Var86 := templ.GetChildren(ctx)1892+ templ_7745c5c3_Var90 := templ.GetChildren(ctx)
1807- if templ_7745c5c3_Var86 == nil {1893+ if templ_7745c5c3_Var90 == nil {
1808- templ_7745c5c3_Var86 = templ.NopComponent1894+ templ_7745c5c3_Var90 = templ.NopComponent
1809 }1895 }
1810 ctx = templ.ClearChildren(ctx)1896 ctx = templ.ClearChildren(ctx)
1811- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 162, "<table><tbody data-for=\"uni\">")1897+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 168, "<table><tbody data-for=\"uni\">")
1812 if templ_7745c5c3_Err != nil {1898 if templ_7745c5c3_Err != nil {
1813 return templ_7745c5c3_Err1899 return templ_7745c5c3_Err
1814 }1900 }
1815 for _, ln := range c.Lines {1901 for _, ln := range c.Lines {
1816- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 163, "<tr class=\"ctx\"><td class=\"ln\">")1902+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 169, "<tr class=\"ctx\"><td class=\"ln\">")
1817 if templ_7745c5c3_Err != nil {1903 if templ_7745c5c3_Err != nil {
1818 return templ_7745c5c3_Err1904 return templ_7745c5c3_Err
1819 }1905 }
1820- var templ_7745c5c3_Var87 string1906+ var templ_7745c5c3_Var91 string
1821- templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Old)1907+ templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Old)
1822 if templ_7745c5c3_Err != nil {1908 if templ_7745c5c3_Err != nil {
1823- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 340, Col: 28}1909+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 358, Col: 28}
1824 }1910 }
1825- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87))1911+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91))
1826 if templ_7745c5c3_Err != nil {1912 if templ_7745c5c3_Err != nil {
1827 return templ_7745c5c3_Err1913 return templ_7745c5c3_Err
1828 }1914 }
1829- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 164, "</td><td class=\"ln\">")1915+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 170, "</td><td class=\"ln\">")
1830 if templ_7745c5c3_Err != nil {1916 if templ_7745c5c3_Err != nil {
1831 return templ_7745c5c3_Err1917 return templ_7745c5c3_Err
1832 }1918 }
1833- var templ_7745c5c3_Var88 string1919+ var templ_7745c5c3_Var92 string
1834- templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(ln.New)1920+ templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.JoinStringErrs(ln.New)
1835 if templ_7745c5c3_Err != nil {1921 if templ_7745c5c3_Err != nil {
1836- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 341, Col: 28}1922+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 359, Col: 28}
1837 }1923 }
1838- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))1924+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var92))
1839 if templ_7745c5c3_Err != nil {1925 if templ_7745c5c3_Err != nil {
1840 return templ_7745c5c3_Err1926 return templ_7745c5c3_Err
1841 }1927 }
1842- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 165, "</td><td class=\"m\">")1928+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 171, "</td><td class=\"m\">")
1843 if templ_7745c5c3_Err != nil {1929 if templ_7745c5c3_Err != nil {
1844 return templ_7745c5c3_Err1930 return templ_7745c5c3_Err
1845 }1931 }
1846- var templ_7745c5c3_Var89 string1932+ var templ_7745c5c3_Var93 string
1847- templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)1933+ templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
1848 if templ_7745c5c3_Err != nil {1934 if templ_7745c5c3_Err != nil {
1849- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 342, Col: 28}1935+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 360, Col: 28}
1850 }1936 }
1851- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))1937+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93))
1852 if templ_7745c5c3_Err != nil {1938 if templ_7745c5c3_Err != nil {
1853 return templ_7745c5c3_Err1939 return templ_7745c5c3_Err
1854 }1940 }
1855- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 166, "</td><td class=\"tx chroma\">")1941+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 172, "</td><td class=\"tx chroma\">")
1856 if templ_7745c5c3_Err != nil {1942 if templ_7745c5c3_Err != nil {
1857 return templ_7745c5c3_Err1943 return templ_7745c5c3_Err
1858 }1944 }
@@ -1860,7 +1946,7 @@ func DiffContext(c ContextRows) templ.Component {
1860 if templ_7745c5c3_Err != nil {1946 if templ_7745c5c3_Err != nil {
1861 return templ_7745c5c3_Err1947 return templ_7745c5c3_Err
1862 }1948 }
1863- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 167, "</td></tr>")1949+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "</td></tr>")
1864 if templ_7745c5c3_Err != nil {1950 if templ_7745c5c3_Err != nil {
1865 return templ_7745c5c3_Err1951 return templ_7745c5c3_Err
1866 }1952 }
@@ -1871,12 +1957,12 @@ func DiffContext(c ContextRows) templ.Component {
1871 return templ_7745c5c3_Err1957 return templ_7745c5c3_Err
1872 }1958 }
1873 }1959 }
1874- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 168, "</tbody> <tbody data-for=\"spl\">")1960+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, "</tbody> <tbody data-for=\"spl\">")
1875 if templ_7745c5c3_Err != nil {1961 if templ_7745c5c3_Err != nil {
1876 return templ_7745c5c3_Err1962 return templ_7745c5c3_Err
1877 }1963 }
1878 for i := range c.Lines {1964 for i := range c.Lines {
1879- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 169, "<tr>")1965+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 175, "<tr>")
1880 if templ_7745c5c3_Err != nil {1966 if templ_7745c5c3_Err != nil {
1881 return templ_7745c5c3_Err1967 return templ_7745c5c3_Err
1882 }1968 }
@@ -1888,7 +1974,7 @@ func DiffContext(c ContextRows) templ.Component {
1888 if templ_7745c5c3_Err != nil {1974 if templ_7745c5c3_Err != nil {
1889 return templ_7745c5c3_Err1975 return templ_7745c5c3_Err
1890 }1976 }
1891- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 170, "</tr>")1977+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 176, "</tr>")
1892 if templ_7745c5c3_Err != nil {1978 if templ_7745c5c3_Err != nil {
1893 return templ_7745c5c3_Err1979 return templ_7745c5c3_Err
1894 }1980 }
@@ -1899,7 +1985,7 @@ func DiffContext(c ContextRows) templ.Component {
1899 return templ_7745c5c3_Err1985 return templ_7745c5c3_Err
1900 }1986 }
1901 }1987 }
1902- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 171, "</tbody></table>")1988+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, "</tbody></table>")
1903 if templ_7745c5c3_Err != nil {1989 if templ_7745c5c3_Err != nil {
1904 return templ_7745c5c3_Err1990 return templ_7745c5c3_Err
1905 }1991 }
@@ -1925,36 +2011,36 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
1925 }()2011 }()
1926 }2012 }
1927 ctx = templ.InitializeContext(ctx)2013 ctx = templ.InitializeContext(ctx)
1928- templ_7745c5c3_Var90 := templ.GetChildren(ctx)2014+ templ_7745c5c3_Var94 := templ.GetChildren(ctx)
1929- if templ_7745c5c3_Var90 == nil {2015+ if templ_7745c5c3_Var94 == nil {
1930- templ_7745c5c3_Var90 = templ.NopComponent2016+ templ_7745c5c3_Var94 = templ.NopComponent
1931 }2017 }
1932 ctx = templ.ClearChildren(ctx)2018 ctx = templ.ClearChildren(ctx)
1933 if ln == nil {2019 if ln == nil {
1934- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 172, "<td class=\"ln none\"></td><td class=\"m none\"></td><td class=\"tx none\"></td>")2020+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 178, "<td class=\"ln none\"></td><td class=\"m none\"></td><td class=\"tx none\"></td>")
1935 if templ_7745c5c3_Err != nil {2021 if templ_7745c5c3_Err != nil {
1936 return templ_7745c5c3_Err2022 return templ_7745c5c3_Err
1937 }2023 }
1938 } else {2024 } else {
1939- var templ_7745c5c3_Var91 = []any{"ln", ln.Kind, templ.KV("sel", ln.Selected)}2025+ var templ_7745c5c3_Var95 = []any{"ln", ln.Kind, templ.KV("sel", ln.Selected)}
1940- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var91...)2026+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var95...)
1941 if templ_7745c5c3_Err != nil {2027 if templ_7745c5c3_Err != nil {
1942 return templ_7745c5c3_Err2028 return templ_7745c5c3_Err
1943 }2029 }
1944- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "<td class=\"")2030+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 179, "<td class=\"")
1945 if templ_7745c5c3_Err != nil {2031 if templ_7745c5c3_Err != nil {
1946 return templ_7745c5c3_Err2032 return templ_7745c5c3_Err
1947 }2033 }
1948- var templ_7745c5c3_Var92 string2034+ var templ_7745c5c3_Var96 string
1949- templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var91).String())2035+ templ_7745c5c3_Var96, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var95).String())
1950 if templ_7745c5c3_Err != nil {2036 if templ_7745c5c3_Err != nil {
1951 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}2037 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
1952 }2038 }
1953- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var92)2039+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var96)
1954 if templ_7745c5c3_Err != nil {2040 if templ_7745c5c3_Err != nil {
1955 return templ_7745c5c3_Err2041 return templ_7745c5c3_Err
1956 }2042 }
1957- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, "\">")2043+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, "\">")
1958 if templ_7745c5c3_Err != nil {2044 if templ_7745c5c3_Err != nil {
1959 return templ_7745c5c3_Err2045 return templ_7745c5c3_Err
1960 }2046 }
@@ -1969,64 +2055,64 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
1969 return templ_7745c5c3_Err2055 return templ_7745c5c3_Err
1970 }2056 }
1971 }2057 }
1972- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 175, "</td>")2058+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 181, "</td>")
1973 if templ_7745c5c3_Err != nil {2059 if templ_7745c5c3_Err != nil {
1974 return templ_7745c5c3_Err2060 return templ_7745c5c3_Err
1975 }2061 }
1976- var templ_7745c5c3_Var93 = []any{"m", ln.Kind, templ.KV("sel", ln.Selected)}2062+ var templ_7745c5c3_Var97 = []any{"m", ln.Kind, templ.KV("sel", ln.Selected)}
1977- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var93...)2063+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var97...)
1978 if templ_7745c5c3_Err != nil {2064 if templ_7745c5c3_Err != nil {
1979 return templ_7745c5c3_Err2065 return templ_7745c5c3_Err
1980 }2066 }
1981- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 176, "<td class=\"")2067+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 182, "<td class=\"")
1982 if templ_7745c5c3_Err != nil {2068 if templ_7745c5c3_Err != nil {
1983 return templ_7745c5c3_Err2069 return templ_7745c5c3_Err
1984 }2070 }
1985- var templ_7745c5c3_Var94 string2071+ var templ_7745c5c3_Var98 string
1986- templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var93).String())2072+ templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var97).String())
1987 if templ_7745c5c3_Err != nil {2073 if templ_7745c5c3_Err != nil {
1988 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}2074 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
1989 }2075 }
1990- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var94)2076+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var98)
1991 if templ_7745c5c3_Err != nil {2077 if templ_7745c5c3_Err != nil {
1992 return templ_7745c5c3_Err2078 return templ_7745c5c3_Err
1993 }2079 }
1994- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, "\">")2080+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 183, "\">")
1995 if templ_7745c5c3_Err != nil {2081 if templ_7745c5c3_Err != nil {
1996 return templ_7745c5c3_Err2082 return templ_7745c5c3_Err
1997 }2083 }
1998- var templ_7745c5c3_Var95 string2084+ var templ_7745c5c3_Var99 string
1999- templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)2085+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(ln.Mark)
2000 if templ_7745c5c3_Err != nil {2086 if templ_7745c5c3_Err != nil {
2001- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 379, Col: 68}2087+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 397, Col: 68}
2002 }2088 }
2003- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))2089+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
2004 if templ_7745c5c3_Err != nil {2090 if templ_7745c5c3_Err != nil {
2005 return templ_7745c5c3_Err2091 return templ_7745c5c3_Err
2006 }2092 }
2007- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 178, "</td>")2093+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, "</td>")
2008 if templ_7745c5c3_Err != nil {2094 if templ_7745c5c3_Err != nil {
2009 return templ_7745c5c3_Err2095 return templ_7745c5c3_Err
2010 }2096 }
2011- var templ_7745c5c3_Var96 = []any{"tx", "chroma", ln.Kind, templ.KV("sel", ln.Selected)}2097+ var templ_7745c5c3_Var100 = []any{"tx", "chroma", ln.Kind, templ.KV("sel", ln.Selected)}
2012- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var96...)2098+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var100...)
2013 if templ_7745c5c3_Err != nil {2099 if templ_7745c5c3_Err != nil {
2014 return templ_7745c5c3_Err2100 return templ_7745c5c3_Err
2015 }2101 }
2016- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 179, "<td class=\"")2102+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "<td class=\"")
2017 if templ_7745c5c3_Err != nil {2103 if templ_7745c5c3_Err != nil {
2018 return templ_7745c5c3_Err2104 return templ_7745c5c3_Err
2019 }2105 }
2020- var templ_7745c5c3_Var97 string2106+ var templ_7745c5c3_Var101 string
2021- templ_7745c5c3_Var97, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var96).String())2107+ templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var100).String())
2022 if templ_7745c5c3_Err != nil {2108 if templ_7745c5c3_Err != nil {
2023 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}2109 return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 1, Col: 0}
2024 }2110 }
2025- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var97)2111+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var101)
2026 if templ_7745c5c3_Err != nil {2112 if templ_7745c5c3_Err != nil {
2027 return templ_7745c5c3_Err2113 return templ_7745c5c3_Err
2028 }2114 }
2029- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, "\">")2115+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "\">")
2030 if templ_7745c5c3_Err != nil {2116 if templ_7745c5c3_Err != nil {
2031 return templ_7745c5c3_Err2117 return templ_7745c5c3_Err
2032 }2118 }
@@ -2034,7 +2120,7 @@ func splitSide(ln *DiffLine, old bool) templ.Component {
2034 if templ_7745c5c3_Err != nil {2120 if templ_7745c5c3_Err != nil {
2035 return templ_7745c5c3_Err2121 return templ_7745c5c3_Err
2036 }2122 }
2037- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 181, "</td>")2123+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, "</td>")
2038 if templ_7745c5c3_Err != nil {2124 if templ_7745c5c3_Err != nil {
2039 return templ_7745c5c3_Err2125 return templ_7745c5c3_Err
2040 }2126 }
@@ -2061,49 +2147,49 @@ func gutter(n, href string) templ.Component {
2061 }()2147 }()
2062 }2148 }
2063 ctx = templ.InitializeContext(ctx)2149 ctx = templ.InitializeContext(ctx)
2064- templ_7745c5c3_Var98 := templ.GetChildren(ctx)2150+ templ_7745c5c3_Var102 := templ.GetChildren(ctx)
2065- if templ_7745c5c3_Var98 == nil {2151+ if templ_7745c5c3_Var102 == nil {
2066- templ_7745c5c3_Var98 = templ.NopComponent2152+ templ_7745c5c3_Var102 = templ.NopComponent
2067 }2153 }
2068 ctx = templ.ClearChildren(ctx)2154 ctx = templ.ClearChildren(ctx)
2069 if href != "" {2155 if href != "" {
2070- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 182, "<a href=\"")2156+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, "<a href=\"")
2071 if templ_7745c5c3_Err != nil {2157 if templ_7745c5c3_Err != nil {
2072 return templ_7745c5c3_Err2158 return templ_7745c5c3_Err
2073 }2159 }
2074- var templ_7745c5c3_Var99 templ.SafeURL2160+ var templ_7745c5c3_Var103 templ.SafeURL
2075- templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))2161+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(href))
2076 if templ_7745c5c3_Err != nil {2162 if templ_7745c5c3_Err != nil {
2077- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 388, Col: 31}2163+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 406, Col: 31}
2078 }2164 }
2079- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))2165+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
2080 if templ_7745c5c3_Err != nil {2166 if templ_7745c5c3_Err != nil {
2081 return templ_7745c5c3_Err2167 return templ_7745c5c3_Err
2082 }2168 }
2083- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 183, "\" title=\"comment on this line\">")2169+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, "\" title=\"comment on this line\">")
2084 if templ_7745c5c3_Err != nil {2170 if templ_7745c5c3_Err != nil {
2085 return templ_7745c5c3_Err2171 return templ_7745c5c3_Err
2086 }2172 }
2087- var templ_7745c5c3_Var100 string2173+ var templ_7745c5c3_Var104 string
2088- templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(n)2174+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(n)
2089 if templ_7745c5c3_Err != nil {2175 if templ_7745c5c3_Err != nil {
2090- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 388, Col: 66}2176+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 406, Col: 66}
2091 }2177 }
2092- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))2178+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
2093 if templ_7745c5c3_Err != nil {2179 if templ_7745c5c3_Err != nil {
2094 return templ_7745c5c3_Err2180 return templ_7745c5c3_Err
2095 }2181 }
2096- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, "</a>")2182+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "</a>")
2097 if templ_7745c5c3_Err != nil {2183 if templ_7745c5c3_Err != nil {
2098 return templ_7745c5c3_Err2184 return templ_7745c5c3_Err
2099 }2185 }
2100 } else {2186 } else {
2101- var templ_7745c5c3_Var101 string2187+ var templ_7745c5c3_Var105 string
2102- templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(n)2188+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(n)
2103 if templ_7745c5c3_Err != nil {2189 if templ_7745c5c3_Err != nil {
2104- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 390, Col: 5}2190+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/diff.templ`, Line: 408, Col: 5}
2105 }2191 }
2106- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))2192+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
2107 if templ_7745c5c3_Err != nil {2193 if templ_7745c5c3_Err != nil {
2108 return templ_7745c5c3_Err2194 return templ_7745c5c3_Err
2109 }2195 }
M internal/adapters/web/events.go +2 -0
@@ -50,6 +50,8 @@ import (
5050 //
5151 // home-list data: <li id="repo-<name>">…</li>, or <li id="repo-<name>" data-gone></li>
5252 // for a repository that is deleted or no longer visible
53+// Activity rows carry data-activity: push, MR lifecycle/comment,
54+// or issue lifecycle/comment (never pending moderation or CI).
5355 // repo-last-push data: <dd id="last-push-<name>">…</dd>
5456 // refs-list data: <tbody id="ref-rows">…</tbody>, and again with
5557 // <dl id="refs-kv">…</dl>, the facts of the rail
@@ -50,6 +50,8 @@ import (
50 //50 //
51 // home-list data: <li id="repo-<name>">…</li>, or <li id="repo-<name>" data-gone></li>51 // home-list data: <li id="repo-<name>">…</li>, or <li id="repo-<name>" data-gone></li>
52 // for a repository that is deleted or no longer visible52 // for a repository that is deleted or no longer visible
53+// Activity rows carry data-activity: push, MR lifecycle/comment,
54+// or issue lifecycle/comment (never pending moderation or CI).
53 // repo-last-push data: <dd id="last-push-<name>">…</dd>55 // repo-last-push data: <dd id="last-push-<name>">…</dd>
54 // refs-list data: <tbody id="ref-rows">…</tbody>, and again with56 // refs-list data: <tbody id="ref-rows">…</tbody>, and again with
55 // <dl id="refs-kv">…</dl>, the facts of the rail57 // <dl id="refs-kv">…</dl>, the facts of the rail
M internal/adapters/web/format.go +8 -0
@@ -61,6 +61,14 @@ func grouped(n int) string {
6161 return string(b)
6262 }
6363
64+// viewLabel names a diff layout on the button of the view menu.
65+func viewLabel(view string) string {
66+ if view == "split" {
67+ return "Split"
68+ }
69+ return "Unified"
70+}
71+
6472 func plural(n int, one, many string) string {
6573 if n == 1 {
6674 return "1 " + one
@@ -61,6 +61,14 @@ func grouped(n int) string {
61 return string(b)61 return string(b)
62 }62 }
63 63
64+// viewLabel names a diff layout on the button of the view menu.
65+func viewLabel(view string) string {
66+ if view == "split" {
67+ return "Split"
68+ }
69+ return "Unified"
70+}
71+
64 func plural(n int, one, many string) string {72 func plural(n int, one, many string) string {
65 if n == 1 {73 if n == 1 {
66 return "1 " + one74 return "1 " + one
M internal/adapters/web/fragments.go +18 -0
@@ -112,6 +112,24 @@ func (l *liveStream) home(ctx context.Context, we ports.WatchEvent) ([]fragment,
112112 name = ev.Repo.String()
113113 case domain.PushEvent:
114114 name, fresh = ev.Repo.String(), true
115+ case domain.MergeRequestOpened:
116+ name, fresh = ev.MergeRequest.Repo.String(), true
117+ case domain.MergeRequestMerged:
118+ name, fresh = ev.MergeRequest.Repo.String(), true
119+ case domain.MergeRequestClosed:
120+ name, fresh = ev.MergeRequest.Repo.String(), true
121+ case domain.MergeRequestReady:
122+ name, fresh = ev.MergeRequest.Repo.String(), true
123+ case domain.CommentAdded:
124+ name, fresh = ev.Repo.String(), true
125+ case domain.IssueOpened:
126+ name, fresh = ev.Issue.Repo.String(), true
127+ case domain.IssueClosed:
128+ name, fresh = ev.Issue.Repo.String(), true
129+ case domain.IssueReopened:
130+ name, fresh = ev.Issue.Repo.String(), true
131+ case domain.IssueCommented:
132+ name, fresh = ev.Repo.String(), true
115133 case domain.RunUpdated:
116134 name = ev.Run.Repo.String() // the CI state of the row
117135 case domain.JobUpdated:
@@ -112,6 +112,24 @@ func (l *liveStream) home(ctx context.Context, we ports.WatchEvent) ([]fragment,
112 name = ev.Repo.String()112 name = ev.Repo.String()
113 case domain.PushEvent:113 case domain.PushEvent:
114 name, fresh = ev.Repo.String(), true114 name, fresh = ev.Repo.String(), true
115+ case domain.MergeRequestOpened:
116+ name, fresh = ev.MergeRequest.Repo.String(), true
117+ case domain.MergeRequestMerged:
118+ name, fresh = ev.MergeRequest.Repo.String(), true
119+ case domain.MergeRequestClosed:
120+ name, fresh = ev.MergeRequest.Repo.String(), true
121+ case domain.MergeRequestReady:
122+ name, fresh = ev.MergeRequest.Repo.String(), true
123+ case domain.CommentAdded:
124+ name, fresh = ev.Repo.String(), true
125+ case domain.IssueOpened:
126+ name, fresh = ev.Issue.Repo.String(), true
127+ case domain.IssueClosed:
128+ name, fresh = ev.Issue.Repo.String(), true
129+ case domain.IssueReopened:
130+ name, fresh = ev.Issue.Repo.String(), true
131+ case domain.IssueCommented:
132+ name, fresh = ev.Repo.String(), true
115 case domain.RunUpdated:133 case domain.RunUpdated:
116 name = ev.Run.Repo.String() // the CI state of the row134 name = ev.Run.Repo.String() // the CI state of the row
117 case domain.JobUpdated:135 case domain.JobUpdated:
M internal/adapters/web/home.go +24 -14
@@ -56,12 +56,12 @@ func (s *Server) listRepos(ctx context.Context) ([]ports.RepoView, error) {
5656 // homeSorts are the orders the home list offers, in order. The query also
5757 // accepts "desc" and "branch", which the page does not link to.
5858 var homeSorts = []struct{ key, label string }{
59- {"push", "last push"},
59+ {"activity", "last activity"},
6060 {"name", "name"},
6161 }
6262
6363 // homeKeys are the keys of ?sort= that sortRepos knows.
64-var homeKeys = []string{"push", "name", "desc", "branch"}
64+var homeKeys = []string{"activity", "name", "desc", "branch"}
6565
6666 // sortRepos orders repos by the column key; ties keep the order by name.
6767 func sortRepos(repos []ports.RepoView, key string, desc bool) {
@@ -71,8 +71,8 @@ func sortRepos(repos []ports.RepoView, key string, desc bool) {
7171 return strings.ToLower(a.Description) < strings.ToLower(b.Description)
7272 case "branch":
7373 return a.DefaultBranch < b.DefaultBranch
74- case "push":
75- return a.PushedAt.Before(b.PushedAt)
74+ case "activity":
75+ return repoActiveAt(a).Before(repoActiveAt(b))
7676 }
7777 return a.Name.String() < b.Name.String()
7878 }
@@ -84,17 +84,17 @@ func sortRepos(repos []ports.RepoView, key string, desc bool) {
8484 })
8585 }
8686
87-// home lists the repositories: /?sort=<col>&dir=asc|desc, newest push first
87+// home lists the repositories: /?sort=<col>&dir=asc|desc, newest activity first
8888 // by default.
8989 func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, int, error) {
9090 repos, err := s.listRepos(ctx)
9191 if err != nil {
9292 return nil, 0, err
9393 }
94- key, desc := "push", true
94+ key, desc := "activity", true
9595 for _, k := range homeKeys {
9696 if r.URL.Query().Get("sort") == k {
97- key, desc = k, k == "push"
97+ key, desc = k, k == "activity"
9898 }
9999 }
100100 if d := r.URL.Query().Get("dir"); d == "asc" || d == "desc" {
@@ -103,11 +103,11 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in
103103 sortRepos(repos, key, desc)
104104
105105 now := s.cfg.Now()
106- p := HomePage{}
106+ p := HomePage{Sort: key, Desc: desc}
107107 for _, c := range homeSorts {
108108 sl := SortLink{Label: c.label}
109109 next := "asc"
110- if c.key == "push" {
110+ if c.key == "activity" {
111111 next = "desc"
112112 }
113113 if c.key == key {
@@ -121,11 +121,10 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in
121121 p.Sorts = append(p.Sorts, sl)
122122 }
123123 p.Rows = s.homeRows(ctx, repos, now)
124+ l := s.base()
124125 if n, show := s.inboxCount(ctx); show {
125- p.Inbox = &InboxButton{Href: inboxPath, Count: n}
126+ l.Inbox = &InboxButton{Href: inboxPath, Count: n}
126127 }
127-
128- l := s.base()
129128 l.Title = s.instance
130129 l.Live, l.LiveURL = true, liveURL("home", "")
131130 l.Cmd = append([]CmdItem{{Kind: "go", Label: "home", Href: "/"}}, repoCmds(repos, "")...)
@@ -268,8 +267,8 @@ func homeRow(r ports.RepoView, now time.Time, cursor, signed bool) HomeRow {
268267 Desc: r.Description, Topics: r.Topics, Cursor: cursor,
269268 Private: signed && r.Visibility == domain.VisibilityPrivate,
270269 }
271- if !r.PushedAt.IsZero() {
272- row.Active, row.ActiveAt = ago(now, r.PushedAt), rfc3339(r.PushedAt)
270+ if at := repoActiveAt(r); !at.IsZero() {
271+ row.Active, row.ActiveAt = ago(now, at), rfc3339(at)
273272 }
274273 return row
275274 }
@@ -285,3 +284,14 @@ func repoCmds(repos []ports.RepoView, except string) []CmdItem {
285284 }
286285 return out
287286 }
287+
288+// repoActiveAt falls back for repositories without recorded activity.
289+func repoActiveAt(r ports.RepoView) time.Time {
290+ if !r.ActiveAt.IsZero() {
291+ return r.ActiveAt
292+ }
293+ if r.PushedAt.After(r.CreatedAt) {
294+ return r.PushedAt
295+ }
296+ return r.CreatedAt
297+}
@@ -56,12 +56,12 @@ func (s *Server) listRepos(ctx context.Context) ([]ports.RepoView, error) {
56 // homeSorts are the orders the home list offers, in order. The query also56 // homeSorts are the orders the home list offers, in order. The query also
57 // accepts "desc" and "branch", which the page does not link to.57 // accepts "desc" and "branch", which the page does not link to.
58 var homeSorts = []struct{ key, label string }{58 var homeSorts = []struct{ key, label string }{
59- {"push", "last push"},59+ {"activity", "last activity"},
60 {"name", "name"},60 {"name", "name"},
61 }61 }
62 62
63 // homeKeys are the keys of ?sort= that sortRepos knows.63 // homeKeys are the keys of ?sort= that sortRepos knows.
64-var homeKeys = []string{"push", "name", "desc", "branch"}64+var homeKeys = []string{"activity", "name", "desc", "branch"}
65 65
66 // sortRepos orders repos by the column key; ties keep the order by name.66 // sortRepos orders repos by the column key; ties keep the order by name.
67 func sortRepos(repos []ports.RepoView, key string, desc bool) {67 func sortRepos(repos []ports.RepoView, key string, desc bool) {
@@ -71,8 +71,8 @@ func sortRepos(repos []ports.RepoView, key string, desc bool) {
71 return strings.ToLower(a.Description) < strings.ToLower(b.Description)71 return strings.ToLower(a.Description) < strings.ToLower(b.Description)
72 case "branch":72 case "branch":
73 return a.DefaultBranch < b.DefaultBranch73 return a.DefaultBranch < b.DefaultBranch
74- case "push":74+ case "activity":
75- return a.PushedAt.Before(b.PushedAt)75+ return repoActiveAt(a).Before(repoActiveAt(b))
76 }76 }
77 return a.Name.String() < b.Name.String()77 return a.Name.String() < b.Name.String()
78 }78 }
@@ -84,17 +84,17 @@ func sortRepos(repos []ports.RepoView, key string, desc bool) {
84 })84 })
85 }85 }
86 86
87-// home lists the repositories: /?sort=<col>&dir=asc|desc, newest push first87+// home lists the repositories: /?sort=<col>&dir=asc|desc, newest activity first
88 // by default.88 // by default.
89 func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, int, error) {89 func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, int, error) {
90 repos, err := s.listRepos(ctx)90 repos, err := s.listRepos(ctx)
91 if err != nil {91 if err != nil {
92 return nil, 0, err92 return nil, 0, err
93 }93 }
94- key, desc := "push", true94+ key, desc := "activity", true
95 for _, k := range homeKeys {95 for _, k := range homeKeys {
96 if r.URL.Query().Get("sort") == k {96 if r.URL.Query().Get("sort") == k {
97- key, desc = k, k == "push"97+ key, desc = k, k == "activity"
98 }98 }
99 }99 }
100 if d := r.URL.Query().Get("dir"); d == "asc" || d == "desc" {100 if d := r.URL.Query().Get("dir"); d == "asc" || d == "desc" {
@@ -103,11 +103,11 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in
103 sortRepos(repos, key, desc)103 sortRepos(repos, key, desc)
104 104
105 now := s.cfg.Now()105 now := s.cfg.Now()
106- p := HomePage{}106+ p := HomePage{Sort: key, Desc: desc}
107 for _, c := range homeSorts {107 for _, c := range homeSorts {
108 sl := SortLink{Label: c.label}108 sl := SortLink{Label: c.label}
109 next := "asc"109 next := "asc"
110- if c.key == "push" {110+ if c.key == "activity" {
111 next = "desc"111 next = "desc"
112 }112 }
113 if c.key == key {113 if c.key == key {
@@ -121,11 +121,10 @@ func (s *Server) home(ctx context.Context, r *http.Request) (templ.Component, in
121 p.Sorts = append(p.Sorts, sl)121 p.Sorts = append(p.Sorts, sl)
122 }122 }
123 p.Rows = s.homeRows(ctx, repos, now)123 p.Rows = s.homeRows(ctx, repos, now)
124+ l := s.base()
124 if n, show := s.inboxCount(ctx); show {125 if n, show := s.inboxCount(ctx); show {
125- p.Inbox = &InboxButton{Href: inboxPath, Count: n}126+ l.Inbox = &InboxButton{Href: inboxPath, Count: n}
126 }127 }
127-
128- l := s.base()
129 l.Title = s.instance128 l.Title = s.instance
130 l.Live, l.LiveURL = true, liveURL("home", "")129 l.Live, l.LiveURL = true, liveURL("home", "")
131 l.Cmd = append([]CmdItem{{Kind: "go", Label: "home", Href: "/"}}, repoCmds(repos, "")...)130 l.Cmd = append([]CmdItem{{Kind: "go", Label: "home", Href: "/"}}, repoCmds(repos, "")...)
@@ -268,8 +267,8 @@ func homeRow(r ports.RepoView, now time.Time, cursor, signed bool) HomeRow {
268 Desc: r.Description, Topics: r.Topics, Cursor: cursor,267 Desc: r.Description, Topics: r.Topics, Cursor: cursor,
269 Private: signed && r.Visibility == domain.VisibilityPrivate,268 Private: signed && r.Visibility == domain.VisibilityPrivate,
270 }269 }
271- if !r.PushedAt.IsZero() {270+ if at := repoActiveAt(r); !at.IsZero() {
272- row.Active, row.ActiveAt = ago(now, r.PushedAt), rfc3339(r.PushedAt)271+ row.Active, row.ActiveAt = ago(now, at), rfc3339(at)
273 }272 }
274 return row273 return row
275 }274 }
@@ -285,3 +284,14 @@ func repoCmds(repos []ports.RepoView, except string) []CmdItem {
285 }284 }
286 return out285 return out
287 }286 }
287+
288+// repoActiveAt falls back for repositories without recorded activity.
289+func repoActiveAt(r ports.RepoView) time.Time {
290+ if !r.ActiveAt.IsZero() {
291+ return r.ActiveAt
292+ }
293+ if r.PushedAt.After(r.CreatedAt) {
294+ return r.PushedAt
295+ }
296+ return r.CreatedAt
297+}
M internal/adapters/web/home_test.go +50 -1
@@ -252,7 +252,7 @@ func TestRunUpdatedRefreshesTheHomeRow(t *testing.T) {
252252 assert.Equal(t, "home-list", got[0].event)
253253 assert.Contains(t, got[0].html, `id="repo-proj"`)
254254 assert.Contains(t, got[0].html, "passing")
255- assert.NotContains(t, got[0].html, "new push", "a run is not a push")
255+ assert.NotContains(t, got[0].html, "new activity", "a run is not a push")
256256
257257 // A job that ended refreshes the row too; one in progress does not.
258258 got, err = (&liveStream{s: srv}).render(t.Context(), ports.WatchEvent{Event: domain.JobUpdated{Job: domain.CIJob{Repo: repo, Phase: domain.CIPhaseRunning}}})
@@ -344,3 +344,52 @@ func TestHomeOffersTheLayouts(t *testing.T) {
344344 require.NotEqual(t, -1, store)
345345 assert.Less(t, store, app, "the store loads before the app script")
346346 }
347+
348+func TestHomeActivityOrderAndFallback(t *testing.T) {
349+ t.Parallel()
350+ now := time.Now().UTC()
351+ a, b, c := publicRepo(t, "a"), publicRepo(t, "b"), publicRepo(t, "c")
352+ a.PushedAt = now.Add(-time.Hour)
353+ a.ActiveAt = now
354+ b.PushedAt = now.Add(-time.Minute)
355+ c.CreatedAt = now.Add(-30 * time.Minute)
356+ repos := []ports.RepoView{b, c, a}
357+ sortRepos(repos, "activity", true)
358+ assert.Equal(t, []ports.RepoView{a, b, c}, repos)
359+ sortRepos(repos, "activity", false)
360+ assert.Equal(t, []ports.RepoView{c, b, a}, repos)
361+ assert.Equal(t, rfc3339(now), homeRow(a, now, false, false).ActiveAt)
362+ c.PushedAt = c.CreatedAt.Add(-time.Hour)
363+ assert.Equal(t, c.CreatedAt, repoActiveAt(c), "fallback is the later of creation and push")
364+}
365+
366+func TestActivityEventsRefreshTheHomeRow(t *testing.T) {
367+ t.Parallel()
368+ repo := publicRepo(t, "proj")
369+ srv := newTestServer(t, Config{Repos: reposServing(t, repo), Browse: homeBrowse(t)})
370+ mr := domain.MergeRequest{Repo: repo.Name}
371+ issue := domain.Issue{Repo: repo.Name}
372+ for _, ev := range []domain.Event{
373+ domain.PushEvent{Repo: repo.Name},
374+ domain.MergeRequestOpened{MergeRequest: mr}, domain.MergeRequestMerged{MergeRequest: mr},
375+ domain.MergeRequestClosed{MergeRequest: mr}, domain.MergeRequestReady{MergeRequest: mr},
376+ domain.CommentAdded{Repo: repo.Name}, domain.IssueOpened{Issue: issue},
377+ domain.IssueClosed{Issue: issue}, domain.IssueReopened{Issue: issue}, domain.IssueCommented{Repo: repo.Name},
378+ } {
379+ t.Run(ev.EventKind(), func(t *testing.T) {
380+ t.Parallel()
381+ got, err := (&liveStream{s: srv}).home(t.Context(), ports.WatchEvent{Event: ev})
382+ require.NoError(t, err)
383+ require.Len(t, got, 1)
384+ assert.Equal(t, "home-list", got[0].event)
385+ assert.Contains(t, got[0].html, `id="repo-proj"`)
386+ assert.Contains(t, got[0].html, `data-activity`)
387+ assert.Contains(t, got[0].html, "new activity")
388+ })
389+ }
390+ for _, ev := range []domain.Event{domain.IssueSubmitted{Repo: repo.Name}, domain.IssuePendingRemoved{Repo: repo.Name}} {
391+ got, err := (&liveStream{s: srv}).home(t.Context(), ports.WatchEvent{Event: ev})
392+ require.NoError(t, err)
393+ assert.Empty(t, got)
394+ }
395+}
@@ -252,7 +252,7 @@ func TestRunUpdatedRefreshesTheHomeRow(t *testing.T) {
252 assert.Equal(t, "home-list", got[0].event)252 assert.Equal(t, "home-list", got[0].event)
253 assert.Contains(t, got[0].html, `id="repo-proj"`)253 assert.Contains(t, got[0].html, `id="repo-proj"`)
254 assert.Contains(t, got[0].html, "passing")254 assert.Contains(t, got[0].html, "passing")
255- assert.NotContains(t, got[0].html, "new push", "a run is not a push")255+ assert.NotContains(t, got[0].html, "new activity", "a run is not a push")
256 256
257 // A job that ended refreshes the row too; one in progress does not.257 // A job that ended refreshes the row too; one in progress does not.
258 got, err = (&liveStream{s: srv}).render(t.Context(), ports.WatchEvent{Event: domain.JobUpdated{Job: domain.CIJob{Repo: repo, Phase: domain.CIPhaseRunning}}})258 got, err = (&liveStream{s: srv}).render(t.Context(), ports.WatchEvent{Event: domain.JobUpdated{Job: domain.CIJob{Repo: repo, Phase: domain.CIPhaseRunning}}})
@@ -344,3 +344,52 @@ func TestHomeOffersTheLayouts(t *testing.T) {
344 require.NotEqual(t, -1, store)344 require.NotEqual(t, -1, store)
345 assert.Less(t, store, app, "the store loads before the app script")345 assert.Less(t, store, app, "the store loads before the app script")
346 }346 }
347+
348+func TestHomeActivityOrderAndFallback(t *testing.T) {
349+ t.Parallel()
350+ now := time.Now().UTC()
351+ a, b, c := publicRepo(t, "a"), publicRepo(t, "b"), publicRepo(t, "c")
352+ a.PushedAt = now.Add(-time.Hour)
353+ a.ActiveAt = now
354+ b.PushedAt = now.Add(-time.Minute)
355+ c.CreatedAt = now.Add(-30 * time.Minute)
356+ repos := []ports.RepoView{b, c, a}
357+ sortRepos(repos, "activity", true)
358+ assert.Equal(t, []ports.RepoView{a, b, c}, repos)
359+ sortRepos(repos, "activity", false)
360+ assert.Equal(t, []ports.RepoView{c, b, a}, repos)
361+ assert.Equal(t, rfc3339(now), homeRow(a, now, false, false).ActiveAt)
362+ c.PushedAt = c.CreatedAt.Add(-time.Hour)
363+ assert.Equal(t, c.CreatedAt, repoActiveAt(c), "fallback is the later of creation and push")
364+}
365+
366+func TestActivityEventsRefreshTheHomeRow(t *testing.T) {
367+ t.Parallel()
368+ repo := publicRepo(t, "proj")
369+ srv := newTestServer(t, Config{Repos: reposServing(t, repo), Browse: homeBrowse(t)})
370+ mr := domain.MergeRequest{Repo: repo.Name}
371+ issue := domain.Issue{Repo: repo.Name}
372+ for _, ev := range []domain.Event{
373+ domain.PushEvent{Repo: repo.Name},
374+ domain.MergeRequestOpened{MergeRequest: mr}, domain.MergeRequestMerged{MergeRequest: mr},
375+ domain.MergeRequestClosed{MergeRequest: mr}, domain.MergeRequestReady{MergeRequest: mr},
376+ domain.CommentAdded{Repo: repo.Name}, domain.IssueOpened{Issue: issue},
377+ domain.IssueClosed{Issue: issue}, domain.IssueReopened{Issue: issue}, domain.IssueCommented{Repo: repo.Name},
378+ } {
379+ t.Run(ev.EventKind(), func(t *testing.T) {
380+ t.Parallel()
381+ got, err := (&liveStream{s: srv}).home(t.Context(), ports.WatchEvent{Event: ev})
382+ require.NoError(t, err)
383+ require.Len(t, got, 1)
384+ assert.Equal(t, "home-list", got[0].event)
385+ assert.Contains(t, got[0].html, `id="repo-proj"`)
386+ assert.Contains(t, got[0].html, `data-activity`)
387+ assert.Contains(t, got[0].html, "new activity")
388+ })
389+ }
390+ for _, ev := range []domain.Event{domain.IssueSubmitted{Repo: repo.Name}, domain.IssuePendingRemoved{Repo: repo.Name}} {
391+ got, err := (&liveStream{s: srv}).home(t.Context(), ports.WatchEvent{Event: ev})
392+ require.NoError(t, err)
393+ assert.Empty(t, got)
394+ }
395+}
M internal/adapters/web/issues.templ +24 -22
@@ -136,32 +136,34 @@ templ issueNewRail() {
136136 // owner, the form to comment and the button that closes or reopens it.
137137 templ IssueShow(l Layout, p IssuePage) {
138138 @Shell(l, issueRail(p)) {
139- <header class="show mr-h">
140- <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
141- <dl class="kv show-kv">
142- <dt>state</dt>
143- <dd class="mr-state" data-state={ p.State }>{ p.State }</dd>
144- <dt>opened</dt>
145- <dd>
146- { p.Opened.Name }
147- if p.Opened.WhenAt != "" {
148- { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
139+ <section class="mr-card">
140+ <header class="show mr-h">
141+ <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
142+ <dl class="kv show-kv">
143+ <dt>state</dt>
144+ <dd class="mr-state" data-state={ p.State }>{ p.State }</dd>
145+ <dt>opened</dt>
146+ <dd>
147+ { p.Opened.Name }
148+ if p.Opened.WhenAt != "" {
149+ { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
150+ }
151+ </dd>
152+ if p.UpdatedAt != "" {
153+ <dt>updated</dt>
154+ <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
149155 }
150- </dd>
151- if p.UpdatedAt != "" {
152- <dt>updated</dt>
153- <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
154- }
155- </dl>
156- </header>
156+ </dl>
157+ </header>
158+ if p.Desc != "" {
159+ <article class="mr-desc prose" aria-label="description" hx-ignore>
160+ @templ.Raw(string(p.Desc))
161+ </article>
162+ }
163+ </section>
157164 if p.Live {
158165 @LiveSlot("mr-notice")
159166 }
160- if p.Desc != "" {
161- <article class="mr-desc prose" aria-label="description" hx-ignore>
162- @templ.Raw(string(p.Desc))
163- </article>
164- }
165167 <h2 class="rule-h" id="comments"><span>Comments</span><span class="count">{ itoa(len(p.Comments)) }</span></h2>
166168 for _, c := range p.Comments {
167169 @commentView(c, "")
@@ -136,32 +136,34 @@ templ issueNewRail() {
136 // owner, the form to comment and the button that closes or reopens it.136 // owner, the form to comment and the button that closes or reopens it.
137 templ IssueShow(l Layout, p IssuePage) {137 templ IssueShow(l Layout, p IssuePage) {
138 @Shell(l, issueRail(p)) {138 @Shell(l, issueRail(p)) {
139- <header class="show mr-h">139+ <section class="mr-card">
140- <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>140+ <header class="show mr-h">
141- <dl class="kv show-kv">141+ <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
142- <dt>state</dt>142+ <dl class="kv show-kv">
143- <dd class="mr-state" data-state={ p.State }>{ p.State }</dd>143+ <dt>state</dt>
144- <dt>opened</dt>144+ <dd class="mr-state" data-state={ p.State }>{ p.State }</dd>
145- <dd>145+ <dt>opened</dt>
146- { p.Opened.Name }146+ <dd>
147- if p.Opened.WhenAt != "" {147+ { p.Opened.Name }
148- { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>148+ if p.Opened.WhenAt != "" {
149+ { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
150+ }
151+ </dd>
152+ if p.UpdatedAt != "" {
153+ <dt>updated</dt>
154+ <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
149 }155 }
150- </dd>156+ </dl>
151- if p.UpdatedAt != "" {157+ </header>
152- <dt>updated</dt>158+ if p.Desc != "" {
153- <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>159+ <article class="mr-desc prose" aria-label="description" hx-ignore>
154- }160+ @templ.Raw(string(p.Desc))
155- </dl>161+ </article>
156- </header>162+ }
163+ </section>
157 if p.Live {164 if p.Live {
158 @LiveSlot("mr-notice")165 @LiveSlot("mr-notice")
159 }166 }
160- if p.Desc != "" {
161- <article class="mr-desc prose" aria-label="description" hx-ignore>
162- @templ.Raw(string(p.Desc))
163- </article>
164- }
165 <h2 class="rule-h" id="comments"><span>Comments</span><span class="count">{ itoa(len(p.Comments)) }</span></h2>167 <h2 class="rule-h" id="comments"><span>Comments</span><span class="count">{ itoa(len(p.Comments)) }</span></h2>
166 for _, c := range p.Comments {168 for _, c := range p.Comments {
167 @commentView(c, "")169 @commentView(c, "")
M internal/adapters/web/issues_templ.go +26 -26 generated file: collapsed
M internal/adapters/web/jstest/a11y.test.mjs +25 -0
@@ -8,6 +8,7 @@ import { test } from 'node:test';
88 import { dom, El, el, flushFrames, installDom, settle } from './dom.mjs';
99
1010 // The few things ermite.js uses that dom.mjs does not have.
11+El.prototype.prepend = function (...nodes) { this.nodes.unshift(...this.adopt(nodes)); };
1112 El.prototype.replaceWith = function (n) {
1213 const p = this.parent;
1314 const i = p.nodes.indexOf(this);
@@ -333,3 +334,27 @@ test('the preference is read from storage when the page loads', async () => {
333334 assert.deepEqual(dom.body.events, []);
334335 store.set('keys-off', '');
335336 });
337+
338+
339+test('activity moves a home row up only in newest activity order, preserving focus and cursor', () => {
340+ for (const [sort, desc, activity, moves] of [
341+ ['activity', 'true', true, true],
342+ ['activity', 'false', true, false],
343+ ['name', 'true', true, false],
344+ ['name', 'false', true, false],
345+ ['activity', 'true', false, false], // CI or metadata, not activity
346+ ]) {
347+ const r = rows();
348+ r.list.dataset.sort = sort;
349+ r.list.dataset.desc = desc;
350+ const old = r.list.children[1];
351+ old.setAttribute('data-cursor', '');
352+ active = old.children[0];
353+ const fresh = r.mk('repo-b', '/b');
354+ if (activity) fresh.setAttribute('data-activity', '');
355+ swapWith(`activity-${sort}-${desc}-${activity}`, fresh);
356+ assert.equal(r.list.children.indexOf(fresh), moves ? 0 : 1);
357+ assert.equal(active, fresh.children[0]);
358+ assert.ok(fresh.hasAttribute('data-cursor'));
359+ }
360+});
@@ -8,6 +8,7 @@ import { test } from 'node:test';
8 import { dom, El, el, flushFrames, installDom, settle } from './dom.mjs';8 import { dom, El, el, flushFrames, installDom, settle } from './dom.mjs';
9 9
10 // The few things ermite.js uses that dom.mjs does not have.10 // The few things ermite.js uses that dom.mjs does not have.
11+El.prototype.prepend = function (...nodes) { this.nodes.unshift(...this.adopt(nodes)); };
11 El.prototype.replaceWith = function (n) {12 El.prototype.replaceWith = function (n) {
12 const p = this.parent;13 const p = this.parent;
13 const i = p.nodes.indexOf(this);14 const i = p.nodes.indexOf(this);
@@ -333,3 +334,27 @@ test('the preference is read from storage when the page loads', async () => {
333 assert.deepEqual(dom.body.events, []);334 assert.deepEqual(dom.body.events, []);
334 store.set('keys-off', '');335 store.set('keys-off', '');
335 });336 });
337+
338+
339+test('activity moves a home row up only in newest activity order, preserving focus and cursor', () => {
340+ for (const [sort, desc, activity, moves] of [
341+ ['activity', 'true', true, true],
342+ ['activity', 'false', true, false],
343+ ['name', 'true', true, false],
344+ ['name', 'false', true, false],
345+ ['activity', 'true', false, false], // CI or metadata, not activity
346+ ]) {
347+ const r = rows();
348+ r.list.dataset.sort = sort;
349+ r.list.dataset.desc = desc;
350+ const old = r.list.children[1];
351+ old.setAttribute('data-cursor', '');
352+ active = old.children[0];
353+ const fresh = r.mk('repo-b', '/b');
354+ if (activity) fresh.setAttribute('data-activity', '');
355+ swapWith(`activity-${sort}-${desc}-${activity}`, fresh);
356+ assert.equal(r.list.children.indexOf(fresh), moves ? 0 : 1);
357+ assert.equal(active, fresh.children[0]);
358+ assert.ok(fresh.hasAttribute('data-cursor'));
359+ }
360+});
M internal/adapters/web/keys.templ +1 -0
@@ -32,6 +32,7 @@ templ Keys() {
3232 k-split from:body -> ermite.layout('split');
3333 k-unified from:body -> ermite.layout('unified');
3434 k-collapse from:body -> ermite.collapse();
35+ k-wide from:body -> window.ermiteWide.toggle();
3536 k-expand from:body -> ermite.expandFile();
3637 k-expandAll from:body -> ermite.expandAll();
3738 k-permalink from:body -> ermite.permalink();
@@ -32,6 +32,7 @@ templ Keys() {
32 k-split from:body -> ermite.layout('split');32 k-split from:body -> ermite.layout('split');
33 k-unified from:body -> ermite.layout('unified');33 k-unified from:body -> ermite.layout('unified');
34 k-collapse from:body -> ermite.collapse();34 k-collapse from:body -> ermite.collapse();
35+ k-wide from:body -> window.ermiteWide.toggle();
35 k-expand from:body -> ermite.expandFile();36 k-expand from:body -> ermite.expandFile();
36 k-expandAll from:body -> ermite.expandAll();37 k-expandAll from:body -> ermite.expandAll();
37 k-permalink from:body -> ermite.permalink();38 k-permalink from:body -> ermite.permalink();
M internal/adapters/web/keys_templ.go +1 -1 generated file: collapsed
M internal/adapters/web/mr.go +6 -1
@@ -910,10 +910,15 @@ func (s *Server) placeComments(p *MRPage, repo string, n int64, comments []domai
910910 ln.Selected = true
911911 }
912912 }
913+ // The title names the whole range a shift + click selected: a.go:21-149.
914+ lines := itoa(on.line)
915+ if start < on.line {
916+ lines = itoa(start) + "-" + lines
917+ }
913918 if ln := find(on.path, side, on.line); ln != nil {
914919 ln.Form = &CommentForm{
915920 StartLine: optionalLine(on.start), ID: "cf-line", Action: mrHref(repo, n, "comments"), Path: on.path, Line: itoa(on.line), Side: on.side,
916- Title: "comment on " + visibleText(on.path) + ":" + itoa(on.line) + " (" + on.side + ")",
921+ Title: "comment on " + visibleText(on.path) + ":" + lines + " (" + on.side + ")",
917922 Cancel: withFrom(self, windowStart(fileAt[on.path])) + "#" + fileIDs[on.path], Focus: true,
918923 From: windowStart(fileAt[on.path]),
919924 }
@@ -910,10 +910,15 @@ func (s *Server) placeComments(p *MRPage, repo string, n int64, comments []domai
910 ln.Selected = true910 ln.Selected = true
911 }911 }
912 }912 }
913+ // The title names the whole range a shift + click selected: a.go:21-149.
914+ lines := itoa(on.line)
915+ if start < on.line {
916+ lines = itoa(start) + "-" + lines
917+ }
913 if ln := find(on.path, side, on.line); ln != nil {918 if ln := find(on.path, side, on.line); ln != nil {
914 ln.Form = &CommentForm{919 ln.Form = &CommentForm{
915 StartLine: optionalLine(on.start), ID: "cf-line", Action: mrHref(repo, n, "comments"), Path: on.path, Line: itoa(on.line), Side: on.side,920 StartLine: optionalLine(on.start), ID: "cf-line", Action: mrHref(repo, n, "comments"), Path: on.path, Line: itoa(on.line), Side: on.side,
916- Title: "comment on " + visibleText(on.path) + ":" + itoa(on.line) + " (" + on.side + ")",921+ Title: "comment on " + visibleText(on.path) + ":" + lines + " (" + on.side + ")",
917 Cancel: withFrom(self, windowStart(fileAt[on.path])) + "#" + fileIDs[on.path], Focus: true,922 Cancel: withFrom(self, windowStart(fileAt[on.path])) + "#" + fileIDs[on.path], Focus: true,
918 From: windowStart(fileAt[on.path]),923 From: windowStart(fileAt[on.path]),
919 }924 }
M internal/adapters/web/mr.templ +37 -39
@@ -109,41 +109,43 @@ templ mrListRail(p MRListPage) {
109109 // form, the checks, the settings, the commits and the files.
110110 templ MergeRequest(l Layout, p MRPage) {
111111 @Shell(l, mrRail(p)) {
112- <header class="show mr-h">
113- <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
114- <dl class="kv show-kv">
115- <dt>state</dt>
116- <dd class="mr-state" data-state={ p.State }>
117- { p.State }
118- if p.MergedShort != "" {
119- { " · " }<a href={ templ.SafeURL(p.MergedHref) }>{ p.MergedShort }</a>{ " · " + p.MergeMode }
120- }
121- </dd>
122- <dt>branch</dt>
123- <dd>
124- @branchLink(p.Source, p.SourceHref)
125- { " → " }
126- @branchLink(p.Target, p.TargetHref)
127- </dd>
128- <dt>opened</dt>
129- <dd>
130- { p.Opened.Name }
131- if p.Opened.WhenAt != "" {
132- { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
112+ <section class="mr-card">
113+ <header class="show mr-h">
114+ <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
115+ <dl class="kv show-kv">
116+ <dt>state</dt>
117+ <dd class="mr-state" data-state={ p.State }>
118+ { p.State }
119+ if p.MergedShort != "" {
120+ { " · " }<a href={ templ.SafeURL(p.MergedHref) }>{ p.MergedShort }</a>{ " · " + p.MergeMode }
121+ }
122+ </dd>
123+ <dt>branch</dt>
124+ <dd>
125+ @branchLink(p.Source, p.SourceHref)
126+ { " → " }
127+ @branchLink(p.Target, p.TargetHref)
128+ </dd>
129+ <dt>opened</dt>
130+ <dd>
131+ { p.Opened.Name }
132+ if p.Opened.WhenAt != "" {
133+ { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
134+ }
135+ </dd>
136+ if p.UpdatedAt != "" {
137+ <dt>updated</dt>
138+ <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
133139 }
134- </dd>
135- if p.UpdatedAt != "" {
136- <dt>updated</dt>
137- <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
138- }
139- </dl>
140- </header>
140+ </dl>
141+ </header>
142+ if p.Desc != "" {
143+ <article class="mr-desc prose" aria-label="description" hx-ignore>
144+ @templ.Raw(string(p.Desc))
145+ </article>
146+ }
147+ </section>
141148 @LiveSlot("mr-notice")
142- if p.Desc != "" {
143- <article class="mr-desc prose" aria-label="description" hx-ignore>
144- @templ.Raw(string(p.Desc))
145- </article>
146- }
147149 if p.Since != nil {
148150 <nav class="since" aria-label="Diff range">
149151 <a
@@ -431,9 +433,7 @@ templ mrRail(p MRPage) {
431433 templ mrBar(p MRPage) {
432434 <div class="diff-tools mr-bar" role="group" aria-label="Diff view and merge">
433435 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
434- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)
435- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
436- @collapseButton()
436+ @diffViewMenu(p.DiffView)
437437 <span class="grow"></span>
438438 @MRChecksSum(p.ChecksSum)
439439 if p.Box != nil {
@@ -562,9 +562,7 @@ templ Compare(l Layout, p ComparePage) {
562562 <div class="diff-tools" role="group" aria-label="Diff view">
563563 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
564564 <span class="grow"></span>
565- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)
566- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
567- @collapseButton()
565+ @diffViewMenu(p.DiffView)
568566 </div>
569567 if p.Invisible {
570568 <p class="notice">
@@ -109,41 +109,43 @@ templ mrListRail(p MRListPage) {
109 // form, the checks, the settings, the commits and the files.109 // form, the checks, the settings, the commits and the files.
110 templ MergeRequest(l Layout, p MRPage) {110 templ MergeRequest(l Layout, p MRPage) {
111 @Shell(l, mrRail(p)) {111 @Shell(l, mrRail(p)) {
112- <header class="show mr-h">112+ <section class="mr-card">
113- <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>113+ <header class="show mr-h">
114- <dl class="kv show-kv">114+ <h1><span class="mute">{ p.Number }</span> { p.Title }</h1>
115- <dt>state</dt>115+ <dl class="kv show-kv">
116- <dd class="mr-state" data-state={ p.State }>116+ <dt>state</dt>
117- { p.State }117+ <dd class="mr-state" data-state={ p.State }>
118- if p.MergedShort != "" {118+ { p.State }
119- { " · " }<a href={ templ.SafeURL(p.MergedHref) }>{ p.MergedShort }</a>{ " · " + p.MergeMode }119+ if p.MergedShort != "" {
120- }120+ { " · " }<a href={ templ.SafeURL(p.MergedHref) }>{ p.MergedShort }</a>{ " · " + p.MergeMode }
121- </dd>121+ }
122- <dt>branch</dt>122+ </dd>
123- <dd>123+ <dt>branch</dt>
124- @branchLink(p.Source, p.SourceHref)124+ <dd>
125- { " → " }125+ @branchLink(p.Source, p.SourceHref)
126- @branchLink(p.Target, p.TargetHref)126+ { " → " }
127- </dd>127+ @branchLink(p.Target, p.TargetHref)
128- <dt>opened</dt>128+ </dd>
129- <dd>129+ <dt>opened</dt>
130- { p.Opened.Name }130+ <dd>
131- if p.Opened.WhenAt != "" {131+ { p.Opened.Name }
132- { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>132+ if p.Opened.WhenAt != "" {
133+ { " · " }<time datetime={ p.Opened.WhenAt } title={ p.Opened.Abs }>{ p.Opened.When }</time>
134+ }
135+ </dd>
136+ if p.UpdatedAt != "" {
137+ <dt>updated</dt>
138+ <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>
133 }139 }
134- </dd>140+ </dl>
135- if p.UpdatedAt != "" {141+ </header>
136- <dt>updated</dt>142+ if p.Desc != "" {
137- <dd><time datetime={ p.UpdatedAt }>{ p.Updated }</time></dd>143+ <article class="mr-desc prose" aria-label="description" hx-ignore>
138- }144+ @templ.Raw(string(p.Desc))
139- </dl>145+ </article>
140- </header>146+ }
147+ </section>
141 @LiveSlot("mr-notice")148 @LiveSlot("mr-notice")
142- if p.Desc != "" {
143- <article class="mr-desc prose" aria-label="description" hx-ignore>
144- @templ.Raw(string(p.Desc))
145- </article>
146- }
147 if p.Since != nil {149 if p.Since != nil {
148 <nav class="since" aria-label="Diff range">150 <nav class="since" aria-label="Diff range">
149 <a151 <a
@@ -431,9 +433,7 @@ templ mrRail(p MRPage) {
431 templ mrBar(p MRPage) {433 templ mrBar(p MRPage) {
432 <div class="diff-tools mr-bar" role="group" aria-label="Diff view and merge">434 <div class="diff-tools mr-bar" role="group" aria-label="Diff view and merge">
433 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>435 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
434- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)436+ @diffViewMenu(p.DiffView)
435- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
436- @collapseButton()
437 <span class="grow"></span>437 <span class="grow"></span>
438 @MRChecksSum(p.ChecksSum)438 @MRChecksSum(p.ChecksSum)
439 if p.Box != nil {439 if p.Box != nil {
@@ -562,9 +562,7 @@ templ Compare(l Layout, p ComparePage) {
562 <div class="diff-tools" role="group" aria-label="Diff view">562 <div class="diff-tools" role="group" aria-label="Diff view">
563 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>563 <span class="dim">{ plural(p.NFiles, "file", "files") } · <span class="plus">+{ itoa(p.Adds) }</span> <span class="minus">-{ itoa(p.Dels) }</span></span>
564 <span class="grow"></span>564 <span class="grow"></span>
565- @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref)565+ @diffViewMenu(p.DiffView)
566- @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref)
567- @collapseButton()
568 </div>566 </div>
569 if p.Invisible {567 if p.Invisible {
570 <p class="notice">568 <p class="notice">
M internal/adapters/web/mr_templ.go +107 -123 generated file: collapsed
M internal/adapters/web/overlays.templ +1 -0
@@ -28,6 +28,7 @@ templ OverlayHelp(mr bool) {
2828 <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div>
2929 <div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd> <kbd>m</kbd> <kbd>i</kbd></dt><dd>tabs: summary, files, commits, branches &amp; tags, merge requests, issues</dd></div>
3030 <div><dt><kbd>g h</kbd></dt><dd>home</dd></div>
31+ <div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div>
3132 <div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div>
3233 <div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div>
3334 <div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div>
@@ -28,6 +28,7 @@ templ OverlayHelp(mr bool) {
28 <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div>28 <div><dt><kbd>b</kbd></dt><dd>{ "switch" } branch or tag</dd></div>
29 <div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd> <kbd>m</kbd> <kbd>i</kbd></dt><dd>tabs: summary, files, commits, branches &amp; tags, merge requests, issues</dd></div>29 <div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd> <kbd>m</kbd> <kbd>i</kbd></dt><dd>tabs: summary, files, commits, branches &amp; tags, merge requests, issues</dd></div>
30 <div><dt><kbd>g h</kbd></dt><dd>home</dd></div>30 <div><dt><kbd>g h</kbd></dt><dd>home</dd></div>
31+ <div><dt><kbd>w</kbd></dt><dd>wide mode: use the whole width of the screen, or not (remembered)</dd></div>
31 <div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div>32 <div><dt><kbd>y</kbd></dt><dd>copy a permalink pinned to the commit</dd></div>
32 <div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div>33 <div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse or expand all</dd></div>
33 <div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div>34 <div><dt><kbd>e</kbd> <kbd>E</kbd></dt><dd>diff: the whole file in view / every file, with the lines the hunks hide</dd></div>
M internal/adapters/web/overlays_templ.go +12 -12 generated file: collapsed
M internal/adapters/web/pages.templ +3 -9
M internal/adapters/web/pages_templ.go +205 -223
M internal/adapters/web/shell.templ +14 -1
M internal/adapters/web/shell_templ.go +158 -116
M internal/adapters/web/static/css/20-shell.css +9 -0
M internal/adapters/web/static/css/50-code.css +7 -4
M internal/adapters/web/static/css/55-diff.css +25 -0
M internal/adapters/web/static/css/60-mr.css +15 -1
A internal/adapters/web/static/icons/mailbox.svg +1 -0
M internal/adapters/web/static/js/ermite.js +70 -3
M internal/adapters/web/static/js/mr.js +1 -11
M internal/adapters/web/static/js/store.js +5 -0
M internal/adapters/web/view.go +6 -4
M internal/app/testdata/web/blob-binary.html +8 -1
M internal/app/testdata/web/blob-code.html +8 -1
M internal/app/testdata/web/blob-empty.html +8 -1
M internal/app/testdata/web/blob-image.html +8 -1
M internal/app/testdata/web/blob-markdown.html +8 -1
M internal/app/testdata/web/blob-svg.html +8 -1
M internal/app/testdata/web/blob-text.html +8 -1
M internal/app/testdata/web/blob-too-large.html +8 -1
M internal/app/testdata/web/blob-trojan.html +8 -1
M internal/app/testdata/web/commit-big.html +16 -2
M internal/app/testdata/web/commit-binary.html +16 -2
M internal/app/testdata/web/commit-merge.html +16 -2
M internal/app/testdata/web/commit-modify-split.html +17 -3
M internal/app/testdata/web/commit-modify.html +17 -3
M internal/app/testdata/web/commit-rename.html +17 -3
M internal/app/testdata/web/commit-root.html +20 -6
M internal/app/testdata/web/commit-trojan.html +16 -2
M internal/app/testdata/web/commits-page2.html +8 -1
M internal/app/testdata/web/commits-path.html +8 -1
M internal/app/testdata/web/commits-root.html +8 -1
M internal/app/testdata/web/commits-small.html +8 -1
M internal/app/testdata/web/empty.html +8 -1
M internal/app/testdata/web/home.html +40 -31
M internal/app/testdata/web/not-found-page.html +8 -1
M internal/app/testdata/web/not-found.html +8 -1
M internal/app/testdata/web/refs.html +8 -1
M internal/app/testdata/web/summary.html +8 -1
M internal/app/testdata/web/tree-nested.html +8 -1
M internal/app/testdata/web/tree-root.html +8 -1
M internal/app/testdata/web/tree-slash-ref.html +8 -1
M internal/app/testdata/web/tree-subdir.html +8 -1
M internal/app/web_events_test.go +2 -2
M internal/app/web_mr_test.go +2 -0
M internal/domain/repo.go +1 -0
M internal/ports/dto.go +1 -1
M internal/ports/mocks/RepoMetaStore.go +36 -21
M internal/ports/ports.go +7 -4
A internal/usecase/activity.go +43 -0
A internal/usecase/activity_store_test.go +46 -0
A internal/usecase/activity_test.go +47 -0
M internal/usecase/export_test.go +10 -0
M internal/usecase/issue_moderation.go +1 -0
M internal/usecase/issue_moderation_test.go +1 -0
M internal/usecase/issues.go +3 -0
M internal/usecase/issues_integration_test.go +67 -0
M internal/usecase/issues_test.go +2 -0
M internal/usecase/mergerequests.go +5 -0
M internal/usecase/mergerequests_integration_test.go +11 -0
M internal/usecase/pushes.go +21 -29
M internal/usecase/pushes_test.go +11 -16
A internal/usecase/repo_mutation_test.go +34 -0
M internal/usecase/repos_write.go +6 -14
M internal/usecase/repos_write_test.go +20 -21
M proto/ermite/storage/repo.proto +2 -0

Comments0 open / 0

no comments yet.

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
l
merge request: the list of files (j k move, enter opens, esc back)
M
merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges
R
merge request: mark the head read
esc
close a dialog, leave a field

Branches 2

Tags 42

↑↓ moveenter openesc close