Remove typescript from frontend, go with plain JS

5dd869e68ccb84734c1a7dafe5d757709f1df124

Tucker McKnight <tucker@pangolin.lan> | Sun Nov 16 2025

Remove typescript from frontend, go with plain JS

The added `export {}` statement at the bottom makes it unuseable
in browsers. Apparently the solution is to use webpack, which I'd
rather not do. Not many typescript features were being used in
the frontend anyway.
frontend/main.ts:1
Before
0
1
2
3
4
(function() {
  const setCheckbox = (<any>window).setCheckbox
  const currentTheme = (<any>window).currentTheme

  setCheckbox(currentTheme, document.getElementById('dark-mode-switch'))
After
0
1
2
3
4
(function() {
  const setCheckbox = window.setCheckbox
  const currentTheme = window.currentTheme

  setCheckbox(currentTheme, document.getElementById('dark-mode-switch'))
frontend/main.ts:17
Before
16
17
18
19
20
21
    }, 5000)
  }

  const createClonePopover = (currentRepo: string) => {
    const div = document.createElement('div')
    div.id = "clone-popover"
    div.innerHTML = jsVars.cloneDiv
After
16
17
18
19
20
21
    }, 5000)
  }

  const createClonePopover = () => {
    const div = document.createElement('div')
    div.id = "clone-popover"
    div.innerHTML = jsVars.cloneDiv
frontend/main.ts:32
Before
31
32
33
34
35
36
    div.querySelector("#clone-button").addEventListener('click', copyCommand)

    document.body.addEventListener('click', (event) => {
      const target = event.target as HTMLElement
      // If they didn't click the #clone-popover-btn or if we're not inside of
      // popover, or if we *are* inside of a popover but a different one than the
      // current one, then close the popover.
After
31
32
33
34
35
36
    div.querySelector("#clone-button").addEventListener('click', copyCommand)

    document.body.addEventListener('click', (event) => {
      const target = event.target
      // If they didn't click the #clone-popover-btn or if we're not inside of
      // popover, or if we *are* inside of a popover but a different one than the
      // current one, then close the popover.
frontend/main.ts:62
Before
61
62
63
64
65
66

  const copyPull = (event) => {
    const hash = event.target.dataset.hash
    const originalInnerHtml = event.target.innerHTML
    const copiedAlert = document.createElement('span')
    copiedAlert.innerText = "Copied"
After
61
62
63

64
65

  const copyPull = (event) => {
    const hash = event.target.dataset.hash
⁣
    const copiedAlert = document.createElement('span')
    copiedAlert.innerText = "Copied"
frontend/main.ts:79
Before
78
79
80
81
82
83
84
85
86
    element.addEventListener("click", copyPull)
  })

  const bootstrap = (<any>window).bootstrap
  const jsVars = (<any>window).jsVars

  if (jsVars.nav.repoName) {
    createClonePopover(jsVars.nav.repoName)
  }
}())
After
78
79
80
81
82
83
84
85
86
    element.addEventListener("click", copyPull)
  })

  const bootstrap = window.bootstrap
  const jsVars = window.jsVars

  if (jsVars.nav.repoName) {
    createClonePopover()
  }
}())
frontend/top.ts:1
Before
0
1
2
3
4
(function() {
  const htmlElem = document.querySelector('html')
  window['setMode'] = (mode: string) => {
    localStorage.setItem('theme', mode)
    if (mode === 'dark') {
      htmlElem.setAttribute('data-bs-theme', mode)
After
0
1
2
3
4
(function() {
  const htmlElem = document.querySelector('html')
  window['setMode'] = (mode) => {
    localStorage.setItem('theme', mode)
    if (mode === 'dark') {
      htmlElem.setAttribute('data-bs-theme', mode)
frontend/top.ts:30
Before
29
30
31
32
33
34
    if (mode === 'auto') {
      element.innerHTML = `<i class="bi bi-yin-yang"></i>`
    }
    const link: any = document.getElementById("prism-theme")
    const preferred = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
    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("/")
After
29
30
31
32
33
34
    if (mode === 'auto') {
      element.innerHTML = `<i class="bi bi-yin-yang"></i>`
    }
    const link = document.getElementById("prism-theme")
    const preferred = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
    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("/")
frontend/tsconfig.json:1
Before
0
1
2
3
{
  "compilerOptions": {
    "outDir": "../dist/frontend",
  }
}
After


⁣
⁣
⁣
⁣
make.sh:2
Before
1
2
3

4
5
mkdir -p dist
mkdir -p dist/templates
mkdir -p dist/partial_templates
⁣
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
cp -r vendor dist/
After
1
2
3
4
5
6
mkdir -p dist
mkdir -p dist/templates
mkdir -p dist/partial_templates
cp -r frontend dist/
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
cp -r vendor dist/
package.json:4
Before
3
4
5
6
7
8
9
10
  "version": "0.0.1-alpha.1",
  "main": "dist/main.js",
  "scripts": {
    "build": "npm run schemas && npm run ts && npm run ts-frontend && npm run docs",
    "ts": "./make.sh && npx tsc",
    "ts-frontend": "npx tsc --project frontend",
    "schemas": "npx ts-json-schema-generator --path src/configTypes.ts --type ReposConfiguration > schemas/ReposConfiguration.json",
    "docs": "npx typedoc src/configTypes.ts --readme none"
  },
After
3
4
5
6
7

8
9
  "version": "0.0.1-alpha.1",
  "main": "dist/main.js",
  "scripts": {
    "build": "npm run schemas && npm run ts && npm run docs",
    "ts": "./make.sh && npx tsc",
⁣
    "schemas": "npx ts-json-schema-generator --path src/configTypes.ts --type ReposConfiguration > schemas/ReposConfiguration.json",
    "docs": "npx typedoc src/configTypes.ts --readme none"
  },