Tucker McKnight <tmcknight@instructure.com> | Mon Aug 10 2026
Fix issues where the path did not have a trailing slash Makes the path variable more consistent -- should either just be a slash if the pages are going at the root, or will be like /path/ if it's going in a subdirectory. Makes the branches and tags pages use the nav helper.
73 74 75 76
}
reposConfiguration['repos'] = repos
return reposConfiguration
}73 74 75 76 77 78 79 80 81 82 83 84 85
}
reposConfiguration['repos'] = repos
// Special fixup on the path value, since we expect it
// to always start and end with a slash (or just be a slash).
if (!reposConfiguration.path.endsWith('/')) {
reposConfiguration.path = reposConfiguration.path + '/'
}
if (!reposConfiguration.path.startsWith('/')) {
reposConfiguration.path = '/' + reposConfiguration.path
}
return reposConfiguration
}23 24 25 26 27 28
return branch.repoName === data.flatRef.repoName ?
m('li', [
m('a', {
href: `${data.reposPath}/${slugify(branch.repoName)}/branch/${slugify(branch.refName)}/branches`
}, branch.refName),
branch.refName === data.flatRef.refName
? m('div', {class: "badge rounded-pill bg-secondary mx-1"}, 'current') : null,23 24 25 26 27 28
return branch.repoName === data.flatRef.repoName ?
m('li', [
m('a', {
href: nav.branches({refName: branch.refName, refType: 'branch'})
}, branch.refName),
branch.refName === data.flatRef.refName
? m('div', {class: "badge rounded-pill bg-secondary mx-1"}, 'current') : null,3 4 5 6 7 8
export default async (template, reposConfiguration, eleventyConfig) => {
return async (data) => {
const opts = await template(reposConfiguration, eleventyConfig, data)
const rootPath = opts.rootPath == '/' ? '' : opts.rootPath
return render([
m.trust('<!doctype html>'),3 4 5 6 7
export default async (template, reposConfiguration, eleventyConfig) => {
return async (data) => {
const opts = await template(reposConfiguration, eleventyConfig, data)
return render([
m.trust('<!doctype html>'),12 13 14 15 16 17 18 19
m('meta', {charset: "utf-8"}),
m('meta', {name: "viewport", content: "width=device-width, initial-scale=1"}),
m('title', opts.pageTitle),
m('link', {rel: "stylesheet", href: `${rootPath}/css/design-board.css`}),
opts.additionalHeadContent || null,
m('script', {src: `${rootPath}/frontend/top.js`}),
]),
m('body', [
m('div', {class: "container-fluid container-lg"}, [12 13 14 15 16 17 18 19
m('meta', {charset: "utf-8"}),
m('meta', {name: "viewport", content: "width=device-width, initial-scale=1"}),
m('title', opts.pageTitle),
m('link', {rel: "stylesheet", href: `${opts.rootPath}css/design-board.css`}),
opts.additionalHeadContent || null,
m('script', {src: `${opts.rootPath}frontend/top.js`}),
]),
m('body', [
m('div', {class: "container-fluid container-lg"}, [61 62 63 64 65 66
integrity: "sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI",
crossorigin: "anonymous"
}),
m('script', {src: `${rootPath}/frontend/main-frontend.bundle.js`})
])
])
])61 62 63 64 65 66
integrity: "sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI",
crossorigin: "anonymous"
}),
m('script', {src: `${opts.rootPath}frontend/main-frontend.bundle.js`})
])
])
])55 56 57 58 59 60
rel: "stylesheet",
id: "prism-theme",
type: "text/css",
href: `${data.reposPath}/vendor/prism.css`
}),
],
navbarContent: m('nav', {class: "navbar navbar-expand flex-wrap"}, [55 56 57 58 59 60
rel: "stylesheet",
id: "prism-theme",
type: "text/css",
href: `${nav.rootPath()}vendor/prism.css`
}),
],
navbarContent: m('nav', {class: "navbar navbar-expand flex-wrap"}, [15 16 17 18 19
const slugify = eleventyConfig.getFilter("slugify")
return render([
m.trust('<?xml version="1.0" encoding="utf-8"?>'),
m('feed', {xmlns: "http://www.w3.org/2005/Atom"}, [15 16 17 18 19 20
const slugify = eleventyConfig.getFilter("slugify")
// TODO: use nav for baseUrl + /repos/ part below
return render([
m.trust('<?xml version="1.0" encoding="utf-8"?>'),
m('feed', {xmlns: "http://www.w3.org/2005/Atom"}, [20 21 22 23 24 25 26 27 28 29 30 31 32
// These two aren't actually used by any pages, but they're in almost
// every page URL. E.g. all of them start with 'repos/my-repo-name'
// or 'repos/my-repo-name/branches.'
const repoBasePath = `${reposPath}/${args.slugify(args.currentRepoName)}`
const refPath = (refName, refType) => {
if (refType === 'commit'
|| (refType === 'branch' && refName === args.reposConfig.repos[args.currentRepoName].defaultBranch)) {
return repoBasePath
}
return `${repoBasePath}/${refType}/${args.slugify(refName)}`
}
type RefArgument = {20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// These two aren't actually used by any pages, but they're in almost
// every page URL. E.g. all of them start with 'repos/my-repo-name'
// or 'repos/my-repo-name/branches.'
const repoBasePath = (repoName: string | null = null) => {
return `${reposPath}${args.slugify(repoName || args.currentRepoName)}`
}
const refPath = (refName, refType) => {
if (refType === 'commit'
|| (refType === 'branch' && refName === args.reposConfig.repos[args.currentRepoName].defaultBranch)) {
return repoBasePath()
}
return `${repoBasePath()}/${refType}/${args.slugify(refName)}`
}
type RefArgument = {37 38 39 40 41 42 43 44 45 46 47 48 49 50
return {
rootPath: () => {
if (reposPath === "") {
return "/"
}
else {
return reposPath + '/'
}
},
repoHomePath: () => {
return repoBasePath
},
refHome: (newRef: RefArgument = null) => {
const refName = newRef?.refName || args.currentRefName37 38 39 40 41 42 43 44 45 46 47
return {
rootPath: () => {
return reposPath
},
repoHomePath: (newRepo: string | null = null) => {
// defaults to the currently-initialized repo (args.currentRepoName)
// if newRepo is null
return repoBasePath(newRepo)
},
refHome: (newRef: RefArgument = null) => {
const refName = newRef?.refName || args.currentRefName82 83 84 85 86 87
return `${refPath(refName, refType)}/files`
},
commit: (hash: string) => {
return `${repoBasePath}/commits/${hash}`
},
commits: (pageNum: number, newRef: RefArgument = null) => {
const refName = newRef?.refName || args.currentRefName82 83 84 85 86 87
return `${refPath(refName, refType)}/files`
},
commit: (hash: string) => {
return `${repoBasePath()}/commits/${hash}`
},
commits: (pageNum: number, newRef: RefArgument = null) => {
const refName = newRef?.refName || args.currentRefName108 109 110 111 112 113
return `${refPath(refName, refType)}/commits.xml`
},
homepageButtons: args.reposConfig.repos[args.currentRepoName].defaultTemplate.homepageButtons
}
}
108 109 110 111 112 113 114 115
return `${refPath(refName, refType)}/commits.xml`
},
homepageButtons: () => {
return args.reposConfig.repos[args.currentRepoName].defaultTemplate.homepageButtons
}
}
}
0 1 2 3 4 5 6 7
import m from 'mithril'
import render from 'mithril-node-render'
export default (_reposConfig: any, eleventyConfig: any, data: any) => {
const slugify = eleventyConfig.getFilter("slugify")
const pageContent = m('div', {class: "container"}, [
m('div', {class: "row my-3"},
m('div', {class: "col"},0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import m from 'mithril'
import render from 'mithril-node-render'
import { NavHelper } from './helpers/nav.ts'
export default (reposConfig: any, eleventyConfig: any, data: any) => {
const slugify = eleventyConfig.getFilter("slugify")
const nav = NavHelper({
reposConfig,
slugify,
currentRepoName: '',
currentRefName: '',
currentRefType: 'commit',
})
const pageContent = m('div', {class: "container"}, [
m('div', {class: "row my-3"},
m('div', {class: "col"},15 16 17 18 19 20 21 22 23 24 25 26 27
m('div', {class: "col", style: "flex-basis: 30rem;"},
m('div', {class: "my-2 card bezel-gray flex-grow-1"},
m('div', {class: "card-header"},
m('a', {class: "card-title fs-5", href: `${data.reposPath}/${slugify(repo.name)}`}, repo.name)
),
m('div', {class: "card-body"},
repo.description ? m('p', {class: "card-text"}, repo.description) : null
),
m('div', {class: "card-footer"}, [
m('a', {
href: `${data.reposPath}/${slugify(repo.name)}`,
class: "ms-0 me-2 my-2 btn btn-primary text-white"
}, 'Go to site'),
m('button', {15 16 17 18 19 20 21 22 23 24 25 26 27
m('div', {class: "col", style: "flex-basis: 30rem;"},
m('div', {class: "my-2 card bezel-gray flex-grow-1"},
m('div', {class: "card-header"},
m('a', {class: "card-title fs-5", href: nav.repoHomePath(repo.name)}, repo.name)
),
m('div', {class: "card-body"},
repo.description ? m('p', {class: "card-text"}, repo.description) : null
),
m('div', {class: "card-footer"}, [
m('a', {
href: nav.repoHomePath(repo.name),
class: "ms-0 me-2 my-2 btn btn-primary text-white"
}, 'Go to site'),
m('button', {45 46 47 48 49 50
])
return {
rootPath: `${data.reposPath}/`,
pageTitle: 'Repositories',
pageContent
}45 46 47 48 49 50
])
return {
rootPath: nav.rootPath(),
pageTitle: 'Repositories',
pageContent
}125 126 127 128 129 130
}, 'Copy' )
]),
m('div', {class: "header-button-container"}, [
nav.homepageButtons.map((buttonConfig) => {
return m('a', {
class: "btn btn-secondary",
href: buttonConfig.url,125 126 127 128 129 130
}, 'Copy' )
]),
m('div', {class: "header-button-container"}, [
nav.homepageButtons().map((buttonConfig) => {
return m('a', {
class: "btn btn-secondary",
href: buttonConfig.url,22 23 24 25 26 27
return tag.repoName === data.flatRef.repoName ?
m('li', [
m('a', {
href: `${data.reposPath}/${slugify(tag.repoName)}/tag/${slugify(tag.refName)}/tags`
}, tag.refName),
tag.refName === data.flatRef.refName
? m('div', {class: "badge rounded-pill bg-secondary mx-1"}, 'current') : null,22 23 24 25 26 27
return tag.repoName === data.flatRef.repoName ?
m('li', [
m('a', {
href: nav.tags({refName: tag.refName, refType: 'tag'})
}, tag.refName),
tag.refName === data.flatRef.refName
? m('div', {class: "badge rounded-pill bg-secondary mx-1"}, 'current') : null,308 309 310 311 312 313
// INDEX.TS
eleventyConfig.addTemplate(
'repos/index.11ty.js',
commonPage(indexJsTemplate, {}, eleventyConfig),
{
permalink: `${reposPath}/index.html`,
}308 309 310 311 312 313
// INDEX.TS
eleventyConfig.addTemplate(
'repos/index.11ty.js',
commonPage(indexJsTemplate, reposConfiguration, eleventyConfig),
{
permalink: `${reposPath}/index.html`,
}0 1 2 3
export default {
cloneUrl: (baseUrl: string, repoName: string) => {
return `${baseUrl}/${repoName.toLowerCase().replaceAll(" ", "-")}.git`
}
}0 1 2 3
export default {
cloneUrl: (baseUrl: string, repoName: string) => {
return `${baseUrl}${repoName.toLowerCase().replaceAll(" ", "-")}.git`
}
}