Add patch.njk page

4ccb6eca9b4d6b4e497cc558eb73652a69989e4e

Tucker McKnight | Tue Sep 02 2025

Add patch.njk page

Fix some references to static files that weren't using the
reposPath variable.

Put main.css in the vendors folder, which should be renamed at some
point, but for now it gets main.css into a dist/ location that can
be used by the virutal templates.

Change the way the light/dark theme switcher works; just replace
"prism.css" or "prism_dark.css" instead of replacing the full path.
This avoids having to know the reposPath variable in a JS file.
frontend/top.ts:32
Before
32
33
    const stylesheet = window['currentTheme'] === 'dark' || (window['currentTheme'] === 'auto' && preferred === 'dark') ? "/vendor/prism_dark.css" : "/vendor/prism.css"
    link.href = stylesheet
After
32
33
    const stylesheet = window['currentTheme'] === 'dark' || (window['currentTheme'] === 'auto' && preferred === 'dark') ? "prism_dark.css" : "prism.css"
    link.href = link.href.split("/").slice(0, -1).concat(stylesheet).join("/")
main.ts:4
Before
4
After
4
import flatPatches from './src/flatPatches.ts'
main.ts:34
Before
34
35
    [vendor]: "vendor",
    [frontend]: "frontend"
After
34
35
    [vendor]: `${reposPath}/vendor`,
    [frontend]: `${reposPath}/frontend`,
main.ts:177
Before
177
178
179
    console.log("getreadme")
    console.log(branchName)
    console.log(repoName)
After
177
178
179
  eleventyConfig.addFilter("pagesJustForBranch", (pages, repoName, branchName) => {
    return pages.filter(page => page.repoName === repoName && page.branchName === branchName)
  })

  eleventyConfig.addFilter("date", (dateString) => {
    return new Date(dateString).toDateString()
  })
main.ts:304
Before
304
      branches: branchesData,
After
304
main.ts:325
Before
325
    topLayoutPartial + repoTemplate + bottomLayoutPartial,
After
325
    topLayoutPartial + patchesTemplate + bottomLayoutPartial,
main.ts:336
Before
336
        return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches/page${data.patchPage.pageNumber}`
After
336
        return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches/page${data.patchPage.pageNumber}/`
main.ts:347
Before
347
After
347

  // PATCH.NJK
  const patchTemplate = fsImport.readFileSync(`${__dirname}/templates/patch.njk`).toString()
  const flatPatchesData = await flatPatches(reposConfiguration)
  eleventyConfig.addTemplate(
    `repos/patch.njk`,
    topLayoutPartial + patchTemplate + bottomLayoutPartial,
    {
      pagination: {
        data: "flatPatches",
        size: 1,
        alias: "patchInfo",
      },
      flatPatches: flatPatchesData,
      permalink: (data) => {
        const repoName = data.patchInfo.repoName
        const branchName = data.patchInfo.branchName
        return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches/${data.patchInfo.patch.hash}/`
      },
      eleventyComputed: {
        nav: {
          repoName: (data) => data.patchInfo.repoName,
          branchName: (data) => data.patchInfo.branchName,
        }
      },
      width: "full",
      navTab: "patches",
    }
  )
partial_templates/main_bottom.njk:21
Before
21
22
        window.location = `/repos/${values[0]}/branches/${values[1]}/${values[2]}`
    <script src="/frontend/main.js"></script>
After
21
22
        window.location = `{{reposPath}}/${values[0]}/branches/${values[1]}/${values[2]}`
    <script src="{{reposPath}}/frontend/main.js"></script>
partial_templates/main_top.njk:29
Before
29
30
31
    <script src="/frontend/top.js"></script>
    <link rel="stylesheet" id="prism-theme" type="text/css" href="/vendor/prism.css" />
    <link rel="stylesheet" type="text/css" href="/static/main.css" />
After
29
30
31
    <script src="{{reposPath}}/frontend/top.js"></script>
    <link rel="stylesheet" id="prism-theme" type="text/css" href="{{reposPath}}/vendor/prism.css" />
    <link rel="stylesheet" type="text/css" href="{{reposPath}}/vendor/main.css" />
src/helpers.ts:137
Before
137
  console.log(repoName)
After
137
templates/patch.njk:0
Before
0
After
0
<div class="container-lg">
  <div class="row">
    <div class="col-auto">
      <h1>{{patchInfo.patch.name}}</h2>
      <p>{{patchInfo.patch.date | date }}</p>
      <p>{{patchInfo.patch.author }}</p>
      <pre>{{patchInfo.patch.description}}</pre>
    </div>
  </div>
  <div class="row">
    <div class="col-auto">
      <p class="font-monospace fw-bold text-secondary">{{patchInfo.patch.hash}}</p>
      {% if reposConfig.repos[patchInfo.repoName]._type == "darcs" %}
      <div class="input-group mb-3 d-flex flex-nowrap">
        <span id="clone-command" class="clone input-group-text overflow-hidden">
          {% set url = [reposConfig.baseUrl, "/repos/", patchInfo.repoName | slugify, "/branches/", patchInfo.branchName | slugify] | join | url %}
          darcs pull {{ url }} -h {{patchInfo.patch.hash}}
        </span>
        <button class="btn btn-primary" id="clone-button" onclick="copyCommand()">Copy</button>
      </div>
      {% endif %}
    </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.patch.diffs %}
  {% for hunk in patchHunks %}
    <div class=hunk>
      <span class="font-monospace fw-bold"><a href="/repos/{{patchInfo.repoName | slugify}}/branches/{{patchInfo.branchName | slugify}}/files/{{ hunk.file | slugify}}.html">{{ hunk.file }}:{{ 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.previousText | 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.file | languageExtension(patchInfo.repoName)}}">{{hunk.previousText | 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.file | 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>
templates/patches.njk:12
Before
12
        <span class="patch-name"><a href="/repos/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/patches/{{patch.hash}}">{{patch.name}}</a></span>
After
12
        <span class="patch-name"><a href="{{reposPath}}/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName | slugify}}/patches/{{patch.hash}}">{{patch.name}}</a></span>
templates/patches.njk:27
Before
27
      <a class="page-link {% if pageObj.pageNumber == patchPage.pageNumber %}active{% endif %}" href="/repos/{{patchPage.repoName | slugify}}/branches/{{patchPage.branchName}}/patches/page{{pageObj.pageNumber}}">{{ pageObj.pageNumber }}</a>
After
27
      <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>
vendor/main.css:0
Before
0
After
0
pre {
  font-size: 14px !important;
}
code {
  white-space: pre;
}
blockquote {
  margin-left: 0.25rem;
  padding-left: 0.5rem;
  border-left: 3px solid royalblue;
  background: rgba(125, 125, 125, 0.07);
  overflow: hidden;
}
blockquote p {
  margin: 0.5rem;
}
.hunk {
  box-sizing: border-box;
  margin-bottom: 25px;
}
[data-type=before] mark {
  background-color: rgba(252, 78, 78, .15);
}
[data-type=after] mark {
  background-color: rgba(151, 247, 203, .4);
}
[data-bs-theme=dark] [data-type=after] mark {
  background-color: rgba(51, 247, 160, .1); /* different green for dark mode; looks better */
}
.unified .diff {
  flex-wrap: wrap;
}
.diff-left, .diff-right {
  flex: 1;
  overflow: hidden;
}
.unified .diff-left, .unified .diff-right {
  flex-basis: 100%;
}
.patch {
  margin: 12px 0;
}
.patch-name {
  font-size: 18px;
  font-weight: bold;
}
.patch-hash {
  font-size: 14px;
  margin: 6px 0;
}
.clone {
  font-family: monospace;
  font-size: 12px;
}
.popover {
  max-width: 100%;
}