Luke Jones

lukeonline - commit 4084ccf

fix: allow traversal of all paths4084ccf8ffa6934c2b22afe812acd1d4217e88c7LukeJ<luke.jones.2567@gmail.com>2026-09-29T22:06:34+01:00
diff --git a/src/pages/projects/[name]/files/[...path].astro b/src/pages/projects/[name]/files/[...path].astro index 239005c..b4cf90f 100644 --- a/src/pages/projects/[name]/files/[...path].astro +++ b/src/pages/projects/[name]/files/[...path].astro @@ -2,74 +2,98 @@ import { getCollection } from 'astro:content' import { getTree } from '../../../../lib/repos' import Base from '../../../../layouts/Base.astro' -import { BUTTON_STYLING_SHARED, DISABLED_BUTTON_STYLING_SHARED } from '../../../../consts.ts' export async function getStaticPaths() { const repos = await getCollection('repos') - return repos.map((repo) => ({ - params: { - name: repo.data.name, - }, - props: { - repo, - }, - })) + return repos.flatMap((repo) => { + const tree = getTree(repo.data.name) + + const directories = new Set<string>() + + for (const file of tree) { + const parts = file.path.split('/') + + // Add every directory that exists in the tree. + for (let i = 1; i < parts.length; i++) { + directories.add(parts.slice(0, i).join('/')) + } + } + + return [...directories].map((path) => ({ + params: { + name: repo.data.name, + path, + }, + props: { + repo, + tree, + }, + })) + }) } -const { repo } = Astro.props +const { repo, tree } = Astro.props +const { path } = Astro.params -const tree = getTree(repo.data.name) +const directory = path ?? '' +const prefix = `${directory}/` + +const files = tree + .filter((file) => { + if (!file.path.startsWith(prefix)) { + return false + } + + const remaining = file.path.slice(prefix.length) + + return remaining.length > 0 && !remaining.includes('/') + }) + .sort((a, b) => a.path.localeCompare(b.path)) -const files = tree.filter((file) => !file.path.includes('/')) const directories = [ ...new Set( tree - .filter((file) => file.path.includes('/')) - .map((file) => file.path.split('/')[0]) + .filter((file) => file.path.startsWith(prefix)) + .map((file) => { + const remaining = file.path.slice(prefix.length) + return remaining.split('/')[0] + }) + .filter(Boolean) ), -] +].sort((a, b) => a.localeCompare(b)) --- -<Base title={`${repo.data.name}`}> - <div class="flex flex-row items-baseline gap-2"> - <code class="text-sm">{repo.data.defaultBranch}</code> - <a - class={BUTTON_STYLING_SHARED + ' h-8 p-1 pl-2 items-center gap-3'} - href={`/projects/${repo.data.name}/commits`} - >{repo.data.commitCount} commits</a - > +<Base title={`${repo.data.name} - ${directory}`}> + <div + class="flex flex-col rounded-sm p-2 font-mono text-sm whitespace-pre-line ring inset-shadow-sm ring-gray-600 inset-shadow-gray-400" + > <a - class={BUTTON_STYLING_SHARED + ' h-8 p-1 pl-2 items-center gap-3'} + class="p-0.5 hover:text-blue-800 focus:underline" href={`/projects/${repo.data.name}/files`} - >{tree.length} files</a > - <a - class={BUTTON_STYLING_SHARED + ' h-8 p-1 pl-2 items-center gap-3'} - href={`/projects/${repo.data.name}/file/README.md`} - >README</a - > - <a - class={BUTTON_STYLING_SHARED + ' h-8 p-1 pl-2 items-center gap-3'} - href={`/projects/${repo.data.name}/file/LICENSE`} - >LICENSE</a - > - </div> - <div - class="flex flex-col rounded-sm p-2 ring inset-shadow-sm ring-gray-600 inset-shadow-gray-400 font-mono text-sm whitespace-pre-line"> + ../ + </a> + { - directories.map((directory) => ( - <a class="p-0.5 hover:text-blue-800 focus:underline" href={`/projects/${repo.data.name}/files/${directory}`}> - {directory}/ - </a> + directories.map((child) => ( + <a + class="p-0.5 hover:text-blue-800 focus:underline" + href={`/projects/${repo.data.name}/files/${directory}/${child}`} + > + {child}/ + </a> )) } { files.map((file) => ( - <a class="p-0.5 hover:text-blue-800 focus:underline" href={`/projects/${repo.data.name}/file/${file.path}`}> - {file.path} - </a> + <a + class="p-0.5 hover:text-blue-800 focus:underline" + href={`/projects/${repo.data.name}/file/${file.path}`} + > + {file.path.slice(prefix.length)} + </a> )) } </div> diff --git a/src/pages/projects/[name]/files/index.astro b/src/pages/projects/[name]/files/index.astro new file mode 100644 index 0000000..580d7a2 --- /dev/null +++ b/src/pages/projects/[name]/files/index.astro @@ -0,0 +1,62 @@ +--- +import { getCollection } from 'astro:content' +import { getTree } from '../../../../lib/repos' +import Base from '../../../../layouts/Base.astro' + +export async function getStaticPaths() { + const repos = await getCollection('repos') + + return repos.map((repo) => ({ + params: { + name: repo.data.name, + }, + props: { + repo, + }, + })) +} + +const { repo } = Astro.props + +const tree = getTree(repo.data.name) + +const files = tree + .filter((file) => !file.path.includes('/')) + .sort((a, b) => a.path.localeCompare(b.path)) + +const directories = [ + ...new Set( + tree + .filter((file) => file.path.includes('/')) + .map((file) => file.path.split('/')[0]) + ), +].sort((a, b) => a.localeCompare(b)) +--- + +<Base title={repo.data.name}> + <div + class="flex flex-col rounded-sm p-2 font-mono text-sm whitespace-pre-line ring inset-shadow-sm ring-gray-600 inset-shadow-gray-400" + > + { + directories.map((directory) => ( + <a + class="p-0.5 hover:text-blue-800 focus:underline" + href={`/projects/${repo.data.name}/files/${directory}`} + > + {directory}/ + </a> + )) + } + + { + files.map((file) => ( + <a + class="p-0.5 hover:text-blue-800 focus:underline" + href={`/projects/${repo.data.name}/file/${file.path}`} + > + {file.path} + </a> + )) + } + </div> +</Base>