Add a toggleable rendered markdown page for md files

c96099269241f024408717eaca75db25f26446f4

Tucker McKnight | Wed Dec 31 2025

Add a toggleable rendered markdown page for md files

Adds a toggle switch for showing rendered markdown content or
the un-rendered original file contents.

Page will obey the toggle switch state on page load.

Move the "view raw file" link to a separate row, since the "show blame"
toggle switch doesn't show when the rendered markdown page is showing.

Also change the permalink for raw files so that it has the original
file's extension.
frontend/main.js:47
Before
47
  const annotations = document.getElementById("annotations")
After
47
  setShowLastTouch(isOn)
}

const toggleRenderedContent = (event) => {
  const isOn = event.target.checked
  setRenderedContent(isOn)
}

const renderedContent = document.querySelector(".rendered-content")
const codeContent = document.querySelector(".code-content")
const annotations = document.getElementById("annotations")

const setShowLastTouch = (isOn) => {
frontend/main.js:55
Before
55
After
55
const setRenderedContent = (isOn) => {
  if (isOn) {
    renderedContent.classList.remove("d-none")
    codeContent.classList.add("d-none")
  } else {
    renderedContent.classList.add("d-none")
    codeContent.classList.remove("d-none")
  }
}

document.getElementById("showRenderedContent")?.addEventListener('click', toggleRenderedContent)
frontend/main.js:129
Before
129
After
129

const pageLoadLastTouch = document.getElementById("showLastTouch")
if (pageLoadLastTouch) {
  setShowLastTouch(pageLoadLastTouch.checked)
}

const pageLoadRenderedContent = document.getElementById("showRenderedContent")
if (pageLoadRenderedContent) {
  setRenderedContent(pageLoadRenderedContent.checked)
}
js_templates/file.ts:9
Before
9
After
9
  const renderContentIfAvailable = eleventyConfig.getFilter("renderContentIfAvailable")
js_templates/file.ts:30
Before
30
After
30
        <p><a href="${data.reposPath}/${slugify(data.fileInfo.repoName)}/branches/${slugify(data.fileInfo.branchName)}/raw/${data.fileInfo.file.split('.').map(filePart => slugify(filePart)).join('.')}">View raw file</a></p>
js_templates/file.ts:46
Before
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
77
78
79
80
81
82
83
84
85
86
    `<div class="row py-2">
      <div class="col-auto">
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showLastTouch">
          <label class="form-check-label" for="showLastTouch">Show last line change</label>
      </div>
        <a href="${data.reposPath}/${slugify(data.fileInfo.repoName)}/branches/${slugify(data.fileInfo.branchName)}/raw/${slugify(data.fileInfo.file)}">View raw file</a>
      </div>
    </div>
    <div class="row">
      <div class="col-auto p-0">
        <code style="white-space: pre;"><pre class="language-text">${lineNumbers(await getFileContents(data.fileInfo.repoName, data.fileInfo.branchName, data.fileInfo.file)).map((lineNumber) => {
          return lineNumber
        }).join('\n')}</pre></code>
      </div>
      <div id="annotations" class="col-auto d-none p-0">
        <code style="white-space: pre;"><pre class="language-text">${
          (await getFileLastTouchInfo(
            data.fileInfo.repoName,
            data.fileInfo.branchName,
            data.fileInfo.file
          )).map(
            (annotation) => {
              return `<a href="${data.reposPath}/${slugify(data.fileInfo.repoName)}/branches/${slugify(data.fileInfo.branchName)}/commits/${annotation.sha}">${annotation.sha.substr(0, 6)}</a> ${annotation.author}`
            }
          ).join('\n')
        }</pre></code>
      </div>
      <div class="col overflow-scroll p-0">
        <code>
          ${
            highlightCode(
              await getFileContents(
              ),
              languageExtension(
                data.fileInfo.file,
                data.fileInfo.repoName
              )
            )
          }
        </code>
After
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
77
78
79
80
81
82
83
84
85
86
    `
    ${data.fileInfo.file.endsWith(&quot;.md")
      ? `
        &lt;div class="row">
          <div class="col">
            <div class="form-check form-switch">
              <input class="form-check-input" type="checkbox" role="switch" id="showRenderedContent" checked />
              <label class="form-check-label" for="showRenderedContent">Show rendered markdown</label>
            </div>
          </div>
        <div class="row rendered-content py-4">
          <div class="col">
            ${await renderContentIfAvailable(await getFileContents(
              data.fileInfo.repoName,
              data.fileInfo.branchName,
              data.fileInfo.file
            ), data.fileInfo.branchName)}
          </div>
        </div>
        `
      : ''
    }
    <div class="row code-content ${data.fileInfo.file.endsWith('.md') ? 'd-none' : ''}">
        <div class="row py-2&quot;>
          &lt;div class="col-auto">
            <div class="form-check form-switch">
              <input class="form-check-input" type="checkbox" role="switch" id="showLastTouch">
              <label class="form-check-label" for="showLastTouch">Show last line change</label>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-auto p-0">
            <code style="white-space: pre;"><pre class="language-text">${lineNumbers(await getFileContents(data.fileInfo.repoName, data.fileInfo.branchName, data.fileInfo.file)).map((lineNumber) => {
              return lineNumber
            }).join('\n')}</pre></code>
          </div>
          <div id="annotations" class="col-auto d-none p-0">
            <code style="white-space: pre;"><pre class="language-text">${
              (await getFileLastTouchInfo(
              )).map(
                (annotation) => {
                  return `<a href="${data.reposPath}/${slugify(data.fileInfo.repoName)}/branches/${slugify(data.fileInfo.branchName)}/commits/${annotation.sha}">${annotation.sha.substr(0, 6)}</a> ${annotation.author}`
                }
              ).join('\n')
            }</pre></code>
          </div>
          <div class="col overflow-scroll p-0">
            <code>
              ${
                highlightCode(
                  await getFileContents(
                    data.fileInfo.repoName,
                    data.fileInfo.branchName,
                    data.fileInfo.file
                  ),
                  languageExtension(
                    data.fileInfo.file,
                    data.fileInfo.repoName
                  )
                )
              }
            </code>
          </div>
        </div>
main.ts:352
Before
352
        return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/raw/${eleventyConfig.getFilter("slugify")(data.fileInfo.file)}`
After
352
        return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/raw/${data.fileInfo.file.split('.').map(filePart => eleventyConfig.getFilter("slugify")(filePart)).join('.')}`