Change patch.njk to commit.ts, use new template

be0819677e9561d3eae6cc570a51e080ff388d14

Tucker McKnight | Sat Dec 27 2025

Change patch.njk to commit.ts, use new template

Adds a "Copy" button for copying the hash of the commit.

Made the "Commits" nav item get underlined when it's the active navTab.

Some style tweaks, added a looping template for bezel-color classes.
(The bezel-header class is a special case because it changes colors between
light and dark mode -- not sure what to do about that one yet.)
frontend/main.js:7
Before
7
  const cloneText = elem.dataset.cloneUrl
After
7
  const cloneText = elem.dataset.copyText
frontend/main.js:25
Before
25
      <button data-clone-url='${window.cloneUrl}' class='btn btn-primary shadow-none text-white' id='clone-button'>Copy</button>
After
25
      <button data-copy-text='${window.cloneUrl}' class='btn btn-primary shadow-none text-white' id='copy-button'>Copy</button>
  div.querySelector("#copy-button").addEventListener('click', copyCommand)
frontend/main.js:38
Before
38
39
  div.querySelector("#clone-button").addEventListener('click', copyCommand)
After
38
39
frontend/main.js:103
Before
103
After
103
document.querySelector("#copy-button").addEventListener('click', copyCommand)
js_templates/commit.ts:0
Before
0
After
0
import {NavHelper} from './helpers/nav.ts'

export default async (eleventyConfig: any, data: any, nav: ReturnType<typeof NavHelper>) => {
  const date = eleventyConfig.getFilter("date")
  const slugify = eleventyConfig.getFilter("slugify")
  const lineNumbers = eleventyConfig.getFilter("lineNumbers")
  const languageExtension = eleventyConfig.getFilter("languageExtension")

  return `
    <div class="row">
      <div class="col-auto">
        <div class="bezel-secondary px-3 py-2">
          <h1>${data.patchInfo.commit.message.split('\n')[0]}</h2>
          <div class="input-group mb-2">
            <span class="font-monospace input-group-text border-info text-white text-bg-dark">${data.patchInfo.commit.hash}</span>
            <button data-copy-text='${data.patchInfo.commit.hash}' class="btn btn-info shadow-none" id="copy-button">Copy</button>
          </div>
          <p>${date(data.patchInfo.commit.date)}</p>
          <p>${data.patchInfo.commit.author}</p>
          <pre>${data.patchInfo.commit.message}</pre>
        </div>
      </div>
    </div>
    <div class="row my-4">
      <div class="col-auto">
        <div class="form-check">
          <input class="form-check-input" type="radio" name="unified" id="splitModeSwitch" value="split" onchange="toggleUnifiedMode(this)" checked>
          <label class="form-check-label" for="splitModeSwitch">
            Side-by-side
          </label>
        </div>
        <div class="form-check">
          <input class="form-check-input" type="radio" name="unified" id="unifiedModeSwitch" value="unified" onchange="toggleUnifiedMode(this)">
          <label class="form-check-label" for="unifiedModeSwitch">
            Stacked
          </label>
        </div>
      </div>
    </div>
    <div class="row" id="diffs">
      ${data.patchInfo.commit.diffs.map((hunk) => {
        return `
          <div class=hunk>
            <span class="font-monospace fw-bold"><a href="${data.reposPath}/${slugify(data.patchInfo.repoName)}/branches/${slugify(data.patchInfo.branchName)}/files/${slugify(hunk.fileName)}.html">${hunk.fileName}:${hunk.lineNumber}</a></span>
            <div class="diff d-flex">
              <div class="flex-grow-1 diff-left pe-2">
                <span class='font-monospace text-secondary'>Before</span>
                <div class="row">
                  <div class="col-auto border-end"><pre>
${lineNumbers(hunk.beforeText).map((lineNumber) => {
  return (lineNumber + hunk.lineNumber - 1).toString()
}).join('\n')}</pre></div>
                  <div class="col overflow-scroll">
                    <pre data-start="${hunk.lineNumber}"><code data-type="before" class="line-numbers language-${languageExtension(hunk.fileName, data.patchInfo.repoName)}">${hunk.beforeText}</code></pre>
                  </div>
                </div>
              </div>
              <div class="diff-right flex-grow-1">
                <span class='font-monospace text-secondary'>After</span>
                <div class="row">
                  <div class="col-auto border-end"><pre>
${lineNumbers(hunk.beforeText).map((lineNumber) => {
  return (lineNumber + hunk.lineNumber - 1).toString()
}).join('\n')}</pre></div>
                  <div class="col overflow-scroll">
                    <pre data-start="${hunk.lineNumber}"><code data-type="after" class="line-numbers language-${languageExtension(hunk.fileName, data.patchInfo.repoName)}">${hunk.afterText}</code></pre>
                  </div>
                </div>
              </div>
            </div>
          </div>
        `
      }).join('')}
    </div>

    <script>
      const toggleUnifiedMode = (e) => {
        const diffs = document.getElementById('diffs')
        const afterDiffs = document.querySelectorAll('.diff-right')
        if (e.value == "unified") {
          diffs.classList.add("unified")
        }
        else {
          diffs.classList.remove("unified")
        }
      }
    </script>
  `
}
js_templates/common/htmlPage.ts:118
Before
118
                      <a class="nav-link" href="${nav.repoCurrentBranchCommits()}">Commits</a>
After
118
                      <a class="nav-link ${data.navTab === &#39;commits' ? 'active' : ''}&quot; href="${nav.repoCurrentBranchCommits()}">Commits</a>
js_templates/repo.ts:39
Before
39
        <div class="px-4 pt-3 bezel">
After
39
        <div class="px-4 pt-3 bezel-header">
main.ts:16
Before
16
After
16
import commitJsTemplate from './js_templates/commit.ts'
main.ts:420
Before
420
421

After
420
421
main.ts:459
Before
459
460
461
462
  // PATCH.NJK
  const patchTemplate = fsImport.readFileSync(`${import.meta.dirname}/templates/patch.njk`).toString()
    `repos/patch.njk`,
    topLayoutPartial + patchTemplate + bottomLayoutPartial,
After
459
460
461
462
  // COMMIT.TS
    `repos/commit.11ty.js`,
    htmlPage(reposConfiguration, eleventyConfig, commitJsTemplate),
main.ts:492
Before
492
493
      width: "full",
      navTab: "patches",
After
492
493
      navTab: "commits",
scss/design-board.scss:36
Before
36
.bezel {
After
36
$bezel-colors: ("primary": $primary, "secondary": $secondary, "info": $info, "warning": $warning);

@each $color, $value in $bezel-colors {
  .bezel-#{$color} {
    background-color: $value;
    border-top: 6px solid color.adjust($value, $lightness: 15%);
    border-left: 6px solid color.adjust($value, $lightness: 13%);
    border-bottom: 6px solid color.adjust($value, $lightness: -30%);
    border-right: 6px solid color.adjust($value, $lightness: -40%);
  }
}
@each $color, $value in map-remove($bezel-colors, "info") {
  .bezel-#{$color} {
    color: $body-color-dark;
  }
}

.bezel-header {
scss/design-board.scss:47
Before
47
  .bezel {
After
47
  .bezel-header {
scss/design-board.scss:238
Before
238
After
238


/* Commit page */
.hunk {
  box-sizing: border-box;
  margin-bottom: 25px;
}
.unified .diff {
  flex-wrap: wrap;
}
.diff-left, .diff-right {
  flex: 1;
  overflow: hidden;
}
.unified .diff-left, .unified .diff-right {
  flex-basis: 100%;
}
[data-type=before] mark {
  background-color: rgba(252, 78, 78, .15);
}
[data-type=after] mark, .token.inserted {
  background-color: rgba(170, 227, 203, .35);
}
[data-bs-theme=dark] [data-type=after] mark, [data-bs-theme=dark] .token.inserted {
  background-color: rgba(51, 247, 160, .1); /* different green for dark mode; looks better */
}
templates/patch.njk:1
Before
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<div class="container-lg">
  <div class="row">
    <div class="col-auto">
      <h1>commit first line goes here</h2>
      <p>{{patchInfo.commit.date | date }}</p>
      <p>{{patchInfo.commit.author }}</p>
      <pre>{{patchInfo.commit.message}}</pre>
    </div>
  </div>
  <div class="row">
    <div class="col-auto">
      <p class="font-monospace fw-bold text-secondary">{{patchInfo.commit.hash}}</p>
    </div>
  </div>
</div>
<div class="container-fluid border-top">
  <div class="row my-2">
    <div class="col-auto d-flex align-items-center fs-4">
      <i class="bi bi-layout-split"></i><span class="fs-6 mx-1">Side-by-side</span>
      <div class="form-check form-switch mb-1 px-2">
        <input class="form-check-input mx-0" type="checkbox" id="unifiedModeSwitch" value="unified" onchange="toggleUnifiedMode(this)" aria-label="Toggle switch for stacked or side by side diff view">
      </div>
      <i class="bi bi-hr"></i><span class="fs-6 mx-1">Stacked</span>
    </div>
  </div>
  <div class="row" id="diffs">
  {% set patchHunks = patchInfo.commit.diffs %}
  {% for hunk in patchHunks %}
    <div class=hunk>
      <span class="font-monospace fw-bold"><a href="{{reposPath}}/{{patchInfo.repoName | slugify}}/branches/{{patchInfo.branchName | slugify}}/files/{{ hunk.fileName | slugify}}.html">{{ hunk.fileName }}:{{ hunk.lineNumber }}</a></span>
      <div class="diff d-flex">
        <div class="flex-grow-1 diff-left pe-2">
          <span class='font-monospace text-secondary'>Before</span>
          <div class="row">
            <div class="col-auto border-end">
              <code>
{%- for lineNumber in hunk.beforeText | lineNumbers -%}
{{ lineNumber + hunk.lineNumber - 1}}
{% endfor -%}
              </code>
            </div>
            <div class="col overflow-scroll">
              <pre data-start="{{hunk.lineNumber}}"><code data-type="before" class="line-numbers language-{{hunk.fileName | languageExtension(patchInfo.repoName)}}">{{hunk.beforeText | safe}}</code></pre>
            </div>
          </div>
        </div>
        <div class="diff-right flex-grow-1 ps-2 border-start">
          <span class='font-monospace text-secondary'>After</span>
          <div class="row">
            <div class="col-auto border-end">
              <code>
{%- for lineNumber in hunk.afterText | lineNumbers -%}
{{ lineNumber + hunk.lineNumber - 1}}
{% endfor -%}
              </code>
            </div>
            <div class="col overflow-scroll">
              <pre data-start="{{hunk.lineNumber}}"><code data-type="after" class="line-numbers language-{{hunk.fileName | languageExtension(patchInfo.repoName)}}">{{ hunk.afterText | safe}}</code></pre>
            </div>
          </div>
        </div>
      </div>
    </div>
  {% endfor %}
  </div>
</div>

<script>
  const copyCommand = () => {
    const text = document.getElementById("clone-command").innerText
    const button = document.getElementById("clone-button")
    navigator.clipboard.writeText(text).then(() => {
      button.innerText = "Copied"
    })
  }
</script>
After
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
templates/patches.njk:2
Before
2
      <a class="page-link {% if pageObj.pageNumber == patchPage.pageNumber %}active{% endif %}" href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName}}/patches/page{{pageObj.pageNumber}}">{{ pageObj.pageNumber }}</a>
After
2
      <a class="page-link {% if pageObj.pageNumber == patchPage.pageNumber %}active{% endif %}" href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName}}/commits/page{{pageObj.pageNumber}}">{{ pageObj.pageNumber }}</a>
templates/patches.njk:12
Before
12
        <span class="patch-name"><a href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/patches/{{commit.hash}}">{{commit.message}}</a></span>
After
12
        <span class="patch-name"><a href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/commits/{{commit.hash}}">{{commit.message}}</a></span>