From 745ac9d83234cb060bf802527efd90d301ecc491 Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Wed, 27 May 2026 14:02:36 -0400 Subject: Pull request index --- cgithub/views/pulls.eta | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cgithub/views/pulls.eta (limited to 'cgithub/views/pulls.eta') diff --git a/cgithub/views/pulls.eta b/cgithub/views/pulls.eta new file mode 100644 index 0000000..9ec5ca1 --- /dev/null +++ b/cgithub/views/pulls.eta @@ -0,0 +1,15 @@ +<% layout("./layout"); it.searchType = "pullrequests" %> + + + <% for (const pull of it.pulls) { %> + + + + + + <% } %> +
#<%= pull.number %> + + <%= pull.title %> + +
-- cgit v1.3.1 From 53ac3bc511a45e4e2e3f234a8b8dcf853b0c38d9 Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Fri, 4 Sep 2026 21:26:21 -0400 Subject: Split the page shell out of the repository layout layout.eta was two things at once: the HTML shell every page needs and the repository chrome around it. owner.eta, being the one page that is not about a repository, could use neither and carried its own copy of the shell, which had drifted -- its footer named no build commit and did not link to the original page on GitHub. The shell moves to views/layouts/base.eta, taking its title and any deferred scripts as layout data, and the chrome to views/layouts/repo.eta, a layout over it that adds the clone commands, nav, search box, and the "/" shortcut that focuses it. Repository pages point at repo.eta and render as before; owner.eta uses base.eta directly and so gains the footer it was missing. Templates now live in more than one directory, so scripts/build.ts walks views/ recursively and keys each template by its path underneath it. Names crossing a directory are written from the views root ("/layouts/base.eta"), the one form both Eta's filesystem resolver and the precompiled resolver in worker.ts agree on; siblings stay relative. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ba5p88cWtCq42vf3uweweL --- cgithub/CLAUDE.md | 2 +- cgithub/scripts/build.ts | 20 ++++++-- cgithub/src/app.ts | 2 +- cgithub/src/worker.ts | 5 +- cgithub/views/blob.eta | 2 +- cgithub/views/commits.eta | 2 +- cgithub/views/issues.eta | 2 +- cgithub/views/layout.eta | 66 ------------------------- cgithub/views/layouts/base.eta | 17 +++++++ cgithub/views/layouts/repo.eta | 59 +++++++++++++++++++++++ cgithub/views/owner.eta | 107 ++++++++++++++++++----------------------- cgithub/views/pulls.eta | 2 +- cgithub/views/release.eta | 2 +- cgithub/views/releases.eta | 2 +- cgithub/views/repo.eta | 2 +- cgithub/views/tree.eta | 2 +- cgithub/views/wiki.eta | 2 +- cgithub/views/wikiPages.eta | 2 +- 18 files changed, 156 insertions(+), 142 deletions(-) delete mode 100644 cgithub/views/layout.eta create mode 100644 cgithub/views/layouts/base.eta create mode 100644 cgithub/views/layouts/repo.eta (limited to 'cgithub/views/pulls.eta') diff --git a/cgithub/CLAUDE.md b/cgithub/CLAUDE.md index edb33f5..6c6dc60 100644 --- a/cgithub/CLAUDE.md +++ b/cgithub/CLAUDE.md @@ -24,7 +24,7 @@ pnpm test - `src/worker.ts` - Cloudflare Workers entry (config in `wrangler.jsonc`) - `src/scraper.ts` - GitHub HTML fetching and JSON extraction logic -**Templates:** `views/*.eta` - Eta templates with layout inheritance (`layout.eta` as base). On Workers, runtime code generation is disallowed, so `scripts/build.ts` precompiles templates to `src/views.generated.ts`. The same script records the build's `git describe` output in `src/build.generated.ts` for the page footer. Both are gitignored and regenerated by the `dev`/`deploy` scripts. +**Templates:** `views/*.eta` - Eta templates with layout inheritance. `views/layouts/base.eta` is the HTML shell every page uses; `views/layouts/repo.eta` wraps it with the repository header, nav, and search box. Templates address each other from the views root (`/layouts/base.eta`) or as siblings (`./_tree`). On Workers, runtime code generation is disallowed, so `scripts/build.ts` precompiles templates to `src/views.generated.ts`. The same script records the build's `git describe` output in `src/build.generated.ts` for the page footer. Both are gitignored and regenerated by the `dev`/`deploy` scripts. **Static files:** `public/static/*`, served by Workers Static Assets. diff --git a/cgithub/scripts/build.ts b/cgithub/scripts/build.ts index 76d88a0..4908532 100644 --- a/cgithub/scripts/build.ts +++ b/cgithub/scripts/build.ts @@ -14,10 +14,22 @@ const root = path.join(import.meta.dirname, ".."); const viewsDir = path.join(root, "views"); const eta = new Eta({ views: viewsDir }); -const names = fs - .readdirSync(viewsDir) - .filter((name) => name.endsWith(".eta")) - .sort(); +// Names are the templates' paths under views/, e.g. "layouts/base.eta", which +// is how the templates address each other (see src/worker.ts). +function templateNames(dir: string, prefix = ""): string[] { + const names: string[] = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const name = prefix + entry.name; + if (entry.isDirectory()) { + names.push(...templateNames(path.join(dir, entry.name), `${name}/`)); + } else if (entry.name.endsWith(".eta")) { + names.push(name); + } + } + return names.sort(); +} + +const names = templateNames(viewsDir); let out = `// @ts-nocheck // Generated by scripts/build.ts -- do not edit. diff --git a/cgithub/src/app.ts b/cgithub/src/app.ts index 2fa5832..a040aaa 100644 --- a/cgithub/src/app.ts +++ b/cgithub/src/app.ts @@ -39,7 +39,7 @@ export function createApp(eta: Eta) { const app = new Hono(); app.use(async (c, next) => { - // Include render data for layout.eta. + // Include render data for views/layouts/base.eta. c.setRenderer((template, data) => c.html(eta.render(template, { ...data, githubUrl: githubUrlFor(c), buildCommit })), ); diff --git a/cgithub/src/worker.ts b/cgithub/src/worker.ts index 7bf9100..e59c690 100644 --- a/cgithub/src/worker.ts +++ b/cgithub/src/worker.ts @@ -9,8 +9,11 @@ import { views } from "./views.generated.ts"; // cache: true, Eta serves them from the cache and never compiles. const eta = new Eta({ cache: true }); +// Templates name each other as siblings ("./_tree") or from the views root +// ("/layouts/base.eta"); either way the name is the path under views/ that +// scripts/build.ts keyed the template by. eta.resolvePath = (templatePath: string) => { - let name = templatePath.replace(/^\.\//, ""); + let name = templatePath.replace(/^\.?\//, ""); if (!name.endsWith(".eta")) name += ".eta"; return name; }; diff --git a/cgithub/views/blob.eta b/cgithub/views/blob.eta index 2014b14..9f6706e 100644 --- a/cgithub/views/blob.eta +++ b/cgithub/views/blob.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta"); it.searchType = "code" %> +<% layout("/layouts/repo.eta"); it.searchType = "code" %> <%~ include("./_nav.eta", {...it, view: "blob"}) %> diff --git a/cgithub/views/commits.eta b/cgithub/views/commits.eta index c29693d..a80ef07 100644 --- a/cgithub/views/commits.eta +++ b/cgithub/views/commits.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta") %> +<% layout("/layouts/repo.eta") %> <%~ include("./_nav.eta", {...it, view: "commits"}) %> diff --git a/cgithub/views/issues.eta b/cgithub/views/issues.eta index 646da46..754afb8 100644 --- a/cgithub/views/issues.eta +++ b/cgithub/views/issues.eta @@ -1,4 +1,4 @@ -<% layout("./layout"); it.searchType = "issues" %> +<% layout("/layouts/repo.eta"); it.searchType = "issues" %> <% for (const issue of it.issues) { %> diff --git a/cgithub/views/layout.eta b/cgithub/views/layout.eta deleted file mode 100644 index 37289dd..0000000 --- a/cgithub/views/layout.eta +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - <%= it.repo.owner %>/<%= it.repo.name %> - <%= it.path || '/' %> - - - - -
- -
git clone https://github.com/<%= it.repo.owner %>/<%= it.repo.name %>.git
-git clone git@github.com:<%= it.repo.owner %>/<%= it.repo.name %>.git
- -
- "> - - - -
- - <%~ it.body %> - -
Generated by cgithub commit <%= it.buildCommit %> · View original
- - - - diff --git a/cgithub/views/layouts/base.eta b/cgithub/views/layouts/base.eta new file mode 100644 index 0000000..fb644f5 --- /dev/null +++ b/cgithub/views/layouts/base.eta @@ -0,0 +1,17 @@ + + + + + + <%= it.title %> + + <% for (const src of it.scripts ?? []) { %> + + <% } %> + + + <%~ it.body %> + +
Generated by cgithub commit <%= it.buildCommit %> · View original
+ + diff --git a/cgithub/views/layouts/repo.eta b/cgithub/views/layouts/repo.eta new file mode 100644 index 0000000..e4f7880 --- /dev/null +++ b/cgithub/views/layouts/repo.eta @@ -0,0 +1,59 @@ +<% +layout("/layouts/base.eta", { + title: `${it.repo.owner}/${it.repo.name} - ${it.path || "/"}`, + scripts: ["/static/refs.js"], +}) +%> + +
+ +
git clone https://github.com/<%= it.repo.owner %>/<%= it.repo.name %>.git
+git clone git@github.com:<%= it.repo.owner %>/<%= it.repo.name %>.git
+ +
+ "> + + + +
+ +<%~ it.body %> + + diff --git a/cgithub/views/owner.eta b/cgithub/views/owner.eta index e5667fb..b3304fb 100644 --- a/cgithub/views/owner.eta +++ b/cgithub/views/owner.eta @@ -1,65 +1,54 @@ - - - - - - <%= it.name ? `${it.name} (${it.login})` : it.login %> - - - -
- <% if (it.avatarUrl) { %> - - <% } %> -
<%= it.name || it.login %>
-
<%= it.login %><%= it.type === "organization" ? " (organization)" : "" %>
- <% if (it.location) { %> -
<%= it.location %>
- <% } %> - <% if (it.nav.length > 0) { %> - - <% } %> -
+<% layout("/layouts/base.eta", { title: it.name ? `${it.name} (${it.login})` : it.login }) %> - <% if (it.bio || it.links.length > 0 || it.followers || it.company) { %> -
- <% if (it.bio) { %> -
<%= it.bio %>
- <% } %> - <% for (const link of it.links) { %> - - <% } %> - <% if (it.followers) { %> -
<%= it.followers %> followers<%= it.following ? ` · ${it.following} following` : "" %>
- <% } %> - <% if (it.company) { %> -
<%= it.company %>
- <% } %> -
+
+ <% if (it.avatarUrl) { %> + <% } %> - - <% if (it.pinned.length > 0) { %> -
-

Pinned

- <% for (const repo of it.pinned) { %> - <%~ include("./_ownerRepo", { repo, login: it.login }) %> - <% } %> -
+
<%= it.name || it.login %>
+
<%= it.login %><%= it.type === "organization" ? " (organization)" : "" %>
+ <% if (it.location) { %> +
<%= it.location %>
<% } %> - - <% if (it.repos.length > 0) { %> -
-

Repositories

- <% for (const repo of it.repos) { %> - <%~ include("./_ownerRepo", { repo, login: it.login }) %> + <% if (it.nav.length > 0) { %> +
+ <% } %> +
+ +<% if (it.bio || it.links.length > 0 || it.followers || it.company) { %> +
+ <% if (it.bio) { %> +
<%= it.bio %>
+ <% } %> + <% for (const link of it.links) { %> + + <% } %> + <% if (it.followers) { %> +
<%= it.followers %> followers<%= it.following ? ` · ${it.following} following` : "" %>
+ <% } %> + <% if (it.company) { %> +
<%= it.company %>
+ <% } %> +
+<% } %> -
Generated by cgithub
- - +<% if (it.pinned.length > 0) { %> +
+

Pinned

+ <% for (const repo of it.pinned) { %> + <%~ include("./_ownerRepo", { repo, login: it.login }) %> + <% } %> +
+<% } %> + +<% if (it.repos.length > 0) { %> +
+

Repositories

+ <% for (const repo of it.repos) { %> + <%~ include("./_ownerRepo", { repo, login: it.login }) %> + <% } %> +
+<% } %> diff --git a/cgithub/views/pulls.eta b/cgithub/views/pulls.eta index 9ec5ca1..697f6b1 100644 --- a/cgithub/views/pulls.eta +++ b/cgithub/views/pulls.eta @@ -1,4 +1,4 @@ -<% layout("./layout"); it.searchType = "pullrequests" %> +<% layout("/layouts/repo.eta"); it.searchType = "pullrequests" %>
<% for (const pull of it.pulls) { %> diff --git a/cgithub/views/release.eta b/cgithub/views/release.eta index 46dd5db..64cca35 100644 --- a/cgithub/views/release.eta +++ b/cgithub/views/release.eta @@ -1,3 +1,3 @@ -<% layout("./layout.eta") %> +<% layout("/layouts/repo.eta") %> <%~ include("./_release.eta", { repo: it.repo, release: it.release, linkToDetail: false }) %> diff --git a/cgithub/views/releases.eta b/cgithub/views/releases.eta index 840908c..4ede28b 100644 --- a/cgithub/views/releases.eta +++ b/cgithub/views/releases.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta") %> +<% layout("/layouts/repo.eta") %> <% for (const release of it.releases) { %> <%~ include("./_release.eta", { repo: it.repo, release, linkToDetail: true }) %> diff --git a/cgithub/views/repo.eta b/cgithub/views/repo.eta index 5dc6beb..60746df 100644 --- a/cgithub/views/repo.eta +++ b/cgithub/views/repo.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta") %> +<% layout("/layouts/repo.eta") %> <% if (it.info) { %>
diff --git a/cgithub/views/tree.eta b/cgithub/views/tree.eta index 41ded06..fabf5b9 100644 --- a/cgithub/views/tree.eta +++ b/cgithub/views/tree.eta @@ -1,3 +1,3 @@ -<% layout("./layout.eta"); it.searchType = "code" %> +<% layout("/layouts/repo.eta"); it.searchType = "code" %> <%~ include("./_tree.eta", it) %> diff --git a/cgithub/views/wiki.eta b/cgithub/views/wiki.eta index d6047e1..781caff 100644 --- a/cgithub/views/wiki.eta +++ b/cgithub/views/wiki.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta"); it.path = "wiki/" + it.title %> +<% layout("/layouts/repo.eta"); it.path = "wiki/" + it.title %> <%~ include("./_wikiNav.eta", it) %> diff --git a/cgithub/views/wikiPages.eta b/cgithub/views/wikiPages.eta index 58d6d21..eb90781 100644 --- a/cgithub/views/wikiPages.eta +++ b/cgithub/views/wikiPages.eta @@ -1,4 +1,4 @@ -<% layout("./layout.eta"); it.path = "wiki/_pages" %> +<% layout("/layouts/repo.eta"); it.path = "wiki/_pages" %> <%~ include("./_wikiNav.eta", it) %> -- cgit v1.3.1