website
git clone https://git.pyrossh.dev/website
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
60e980e
— pyrossh
2026-08-05T17:52:57+05:30
improvements
- src/components/theme-switcher.js → assets/client.js +18 -0
- assets/css/shared.css +7 -3
- assets/css/workers/home.css +3 -16
- assets/css/workers/issues-detail.css +1 -5
- assets/css/workers/issues-index.css +1 -5
- assets/css/workers/posts-index.css +2 -10
- eleventy.config.js +0 -7
- infra/main.tf +1 -1
- infra/terraform.tfstate +42 -8
- infra/terraform.tfstate.backup +36 -5
- package.json +1 -1
- src/_helpers/fileIcons.js +43 -1
- src/_includes/layout.njk +1 -1
- src/_includes/repo-layout.njk +2 -2
- src/repos/files-index.njk +1 -1
src/components/theme-switcher.js → assets/client.js
RENAMED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// All client-side JS the site ships, in one plain vanilla file — no
|
|
2
|
+
// bundler needed for two small, independent event listeners.
|
|
3
|
+
|
|
1
4
|
// Wires up the theme button rendered as static markup in site-header.njk
|
|
2
5
|
// (no web component, no framework — a stateless click-to-toggle button
|
|
3
6
|
// doesn't need one). Loaded with `defer` so this runs after the DOM is
|
|
@@ -15,3 +18,18 @@ document.getElementById("theme-change").addEventListener("click", () => {
|
|
|
15
18
|
root.setAttribute("data-theme", next);
|
|
16
19
|
localStorage.setItem("theme", next);
|
|
17
20
|
});
|
|
21
|
+
|
|
22
|
+
// .file-explorer-tree lives outside #file-pane (see the comment on
|
|
23
|
+
// .file-explorer in repos.css) so htmx swaps of #file-pane never re-render
|
|
24
|
+
// it — clicking a file never rebuilds the tree. That's good for keeping
|
|
25
|
+
// scroll position/expanded folders, but it also means the .active-file
|
|
26
|
+
// class painted at page-load time never moves on its own. Move it here,
|
|
27
|
+
// synchronously on click, instead of waiting on htmx's response.
|
|
28
|
+
document.addEventListener("click", (e) => {
|
|
29
|
+
const link = e.target.closest(".file-explorer-tree a");
|
|
30
|
+
if (!link) return;
|
|
31
|
+
const tree = link.closest(".file-explorer-tree");
|
|
32
|
+
const current = tree.querySelector("a.active-file");
|
|
33
|
+
if (current) current.classList.remove("active-file");
|
|
34
|
+
link.classList.add("active-file");
|
|
35
|
+
});
|
assets/css/shared.css
CHANGED
|
@@ -72,7 +72,7 @@ table { border-collapse: collapse; }
|
|
|
72
72
|
--color-text: light-dark(hsl(0, 0%, 13%), hsl(210, 17%, 98%));
|
|
73
73
|
--color-link: light-dark(hsl(211, 100%, 45%), hsl(211, 100%, 60%));
|
|
74
74
|
--color-post-link: light-dark(hsl(0, 0%, 0%), hsl(211, 100%, 60%));
|
|
75
|
-
--color-highlight-bg: light-dark(hsl(
|
|
75
|
+
--color-highlight-bg: light-dark(hsl(210, 10%, 88%), hsl(210, 10%, 24%));
|
|
76
76
|
--color-code-fg: light-dark(hsl(348, 86%, 43%), hsl(348, 86%, 80%));
|
|
77
77
|
--color-code-bg: light-dark(hsl(0, 0%, 89%), hsl(210, 13%, 6%));
|
|
78
78
|
--color-pre-bg: light-dark(hsl(0, 0%, 89%), hsl(210, 13%, 6%));
|
|
@@ -331,10 +331,14 @@ footer {
|
|
|
331
331
|
Prism-highlighted blog-post code and plain markdown-it README code
|
|
332
332
|
fences). It's genuinely cross-cutting rather than owned by one
|
|
333
333
|
component — scoping it to either would mean duplicating the whole token
|
|
334
|
-
palette in the other — so it stays global.
|
|
334
|
+
palette in the other — so it stays global.
|
|
335
|
+
|
|
336
|
+
Background lives on pre.code-view/.markdown-body pre below, not here:
|
|
337
|
+
code[class*="language-"] is inline and wraps a whole multi-line file, so
|
|
338
|
+
giving IT a background paints one box per line box (only as wide as that
|
|
339
|
+
line's text) instead of one clean rectangle behind the block. */
|
|
335
340
|
pre[class*="language-"],
|
|
336
341
|
code[class*="language-"] {
|
|
337
|
-
background: var(--color-pre-bg);
|
|
338
342
|
color: var(--color-text);
|
|
339
343
|
}
|
|
340
344
|
|
assets/css/workers/home.css
CHANGED
|
@@ -30,14 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
.repos {
|
|
32
32
|
display: grid;
|
|
33
|
-
grid-template-columns: auto
|
|
33
|
+
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
|
|
34
34
|
gap: 1rem;
|
|
35
35
|
margin-top: 0.5rem;
|
|
36
|
-
|
|
37
|
-
@media (max-width: 720px) {
|
|
38
|
-
gap: 1rem;
|
|
39
|
-
grid-template-columns: auto;
|
|
40
|
-
}
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
.title {
|
|
@@ -63,12 +58,8 @@
|
|
|
63
58
|
|
|
64
59
|
.gridContainer {
|
|
65
60
|
display: grid;
|
|
66
|
-
grid-template-columns: repeat(
|
|
61
|
+
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
|
|
67
62
|
gap: var(--space-gap-fluid);
|
|
68
|
-
|
|
69
|
-
@media (min-width: 640px) {
|
|
70
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
71
|
-
}
|
|
72
63
|
}
|
|
73
64
|
|
|
74
65
|
.repo {
|
|
@@ -168,14 +159,10 @@
|
|
|
168
159
|
ul {
|
|
169
160
|
display: grid;
|
|
170
161
|
gap: 0.5rem;
|
|
171
|
-
grid-template-columns: auto
|
|
162
|
+
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
|
|
172
163
|
text-align: center;
|
|
173
164
|
margin-top: 0.5rem;
|
|
174
165
|
|
|
175
|
-
@media (max-width: 720px) {
|
|
176
|
-
grid-template-columns: auto auto auto;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
166
|
li {
|
|
180
167
|
display: flex;
|
|
181
168
|
align-items: center;
|
assets/css/workers/issues-detail.css
CHANGED
|
@@ -73,10 +73,6 @@ textarea {
|
|
|
73
73
|
|
|
74
74
|
.comment-actions {
|
|
75
75
|
display: grid;
|
|
76
|
-
grid-template-columns: minmax(
|
|
76
|
+
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
77
77
|
gap: 0.5rem;
|
|
78
|
-
|
|
79
|
-
@media (max-width: 720px) {
|
|
80
|
-
grid-template-columns: 1fr;
|
|
81
|
-
}
|
|
82
78
|
}
|
assets/css/workers/issues-index.css
CHANGED
|
@@ -54,10 +54,6 @@ button {
|
|
|
54
54
|
|
|
55
55
|
.form-row {
|
|
56
56
|
display: grid;
|
|
57
|
-
grid-template-columns:
|
|
57
|
+
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
58
58
|
gap: 0.5rem;
|
|
59
|
-
|
|
60
|
-
@media (max-width: 720px) {
|
|
61
|
-
grid-template-columns: 1fr;
|
|
62
|
-
}
|
|
63
59
|
}
|
assets/css/workers/posts-index.css
CHANGED
|
@@ -16,18 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
li {
|
|
18
18
|
display: grid;
|
|
19
|
-
grid-template-columns: repeat(
|
|
19
|
+
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
20
|
-
gap: 0.
|
|
20
|
+
gap: 0.6rem;
|
|
21
21
|
justify-items: start;
|
|
22
22
|
align-items: end;
|
|
23
23
|
margin-top: 1.25rem;
|
|
24
24
|
line-height: 1.5rem;
|
|
25
25
|
|
|
26
|
-
@media (min-width: 640px) {
|
|
27
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
28
|
-
gap: 0.75rem;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
26
|
a {
|
|
32
27
|
font-size: 1.1rem;
|
|
33
28
|
color: var(--color-post-link);
|
|
@@ -58,9 +53,6 @@ time {
|
|
|
58
53
|
justify-content: flex-end;
|
|
59
54
|
font-size: 1rem;
|
|
60
55
|
line-height: 1.5rem;
|
|
61
|
-
@media (min-width: 640px) {
|
|
62
|
-
margin-left: 1rem;
|
|
63
|
-
}
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
58
|
}
|
eleventy.config.js
CHANGED
|
@@ -47,13 +47,6 @@ export default function (eleventyConfig) {
|
|
|
47
47
|
"node_modules/diff2html/bundles/css/diff2html.min.css": "assets/css/diff2html.min.css",
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
// theme-switcher is the one bit of client-side JS the site ships (real
|
|
51
|
-
// click + localStorage behavior) — plain vanilla script, no bundler
|
|
52
|
-
// needed.
|
|
53
|
-
eleventyConfig.addPassthroughCopy({
|
|
54
|
-
"src/components/theme-switcher.js": "assets/components/theme-switcher.js",
|
|
55
|
-
});
|
|
56
|
-
|
|
57
50
|
// htmx powers no-full-page-reload tab switching on repo pages (Readme/
|
|
58
51
|
// Commits/Files, Contents/History/Blame) — hx-select pulls #repo-content
|
|
59
52
|
// or #file-content out of the fetched static page and swaps it in place.
|
infra/main.tf
CHANGED
|
@@ -66,7 +66,7 @@ resource "terraform_data" "sync_website" {
|
|
|
66
66
|
depends_on = [cloudflare_r2_bucket.website, terraform_data.build_website]
|
|
67
67
|
|
|
68
68
|
provisioner "local-exec" {
|
|
69
|
-
command = "rclone sync ${path.module}/../dist website:${cloudflare_r2_bucket.website.name} --checksum --fast-list -P"
|
|
69
|
+
command = "rclone sync ${path.module}/../dist website:${cloudflare_r2_bucket.website.name} --checksum --fast-list --multi-thread-streams=32 -P "
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
infra/terraform.tfstate
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 4,
|
|
3
3
|
"terraform_version": "1.13.3",
|
|
4
|
-
"serial":
|
|
4
|
+
"serial": 29,
|
|
5
5
|
"lineage": "6cb48eaa-b069-089b-fce3-e277626defab",
|
|
6
6
|
"outputs": {
|
|
7
7
|
"bucket_name": {
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"jurisdiction": "default",
|
|
80
80
|
"min_tls": null,
|
|
81
81
|
"status": {
|
|
82
|
-
"ownership": "
|
|
82
|
+
"ownership": "active",
|
|
83
|
-
"ssl": "
|
|
83
|
+
"ssl": "active"
|
|
84
84
|
},
|
|
85
85
|
"zone_id": "e95a5d8957b75859c814579deebfce33",
|
|
86
86
|
"zone_name": "pyrossh.dev"
|
|
@@ -133,12 +133,12 @@
|
|
|
133
133
|
{
|
|
134
134
|
"schema_version": 0,
|
|
135
135
|
"attributes": {
|
|
136
|
-
"id": "
|
|
136
|
+
"id": "f64c9052-0f71-5705-a183-e85f891292b2",
|
|
137
137
|
"input": null,
|
|
138
138
|
"output": null,
|
|
139
139
|
"triggers_replace": {
|
|
140
140
|
"value": [
|
|
141
|
-
"2026-08-
|
|
141
|
+
"2026-08-05T06:08:43Z"
|
|
142
142
|
],
|
|
143
143
|
"type": [
|
|
144
144
|
"tuple",
|
|
@@ -156,19 +156,53 @@
|
|
|
156
156
|
{
|
|
157
157
|
"mode": "managed",
|
|
158
158
|
"type": "terraform_data",
|
|
159
|
-
"name": "
|
|
159
|
+
"name": "purge_cache",
|
|
160
160
|
"provider": "provider[\"terraform.io/builtin/terraform\"]",
|
|
161
161
|
"instances": [
|
|
162
162
|
{
|
|
163
163
|
"status": "tainted",
|
|
164
164
|
"schema_version": 0,
|
|
165
165
|
"attributes": {
|
|
166
|
-
"id": "
|
|
166
|
+
"id": "7173b400-cbc8-069b-7c74-6fa0bae8b3e2",
|
|
167
|
+
"input": null,
|
|
168
|
+
"output": null,
|
|
169
|
+
"triggers_replace": {
|
|
170
|
+
"value": [
|
|
171
|
+
"2026-08-05T06:27:38Z"
|
|
172
|
+
],
|
|
173
|
+
"type": [
|
|
174
|
+
"tuple",
|
|
175
|
+
[
|
|
176
|
+
"string"
|
|
177
|
+
]
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"sensitive_attributes": [],
|
|
182
|
+
"identity_schema_version": 0,
|
|
183
|
+
"dependencies": [
|
|
184
|
+
"cloudflare_r2_bucket.website",
|
|
185
|
+
"terraform_data.build_website",
|
|
186
|
+
"terraform_data.sync_website"
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"mode": "managed",
|
|
193
|
+
"type": "terraform_data",
|
|
194
|
+
"name": "sync_website",
|
|
195
|
+
"provider": "provider[\"terraform.io/builtin/terraform\"]",
|
|
196
|
+
"instances": [
|
|
197
|
+
{
|
|
198
|
+
"schema_version": 0,
|
|
199
|
+
"attributes": {
|
|
200
|
+
"id": "1fe8b333-1b40-c0c6-b113-1e7ce0519af8",
|
|
167
201
|
"input": null,
|
|
168
202
|
"output": null,
|
|
169
203
|
"triggers_replace": {
|
|
170
204
|
"value": [
|
|
171
|
-
"2026-08-
|
|
205
|
+
"2026-08-05T06:09:03Z"
|
|
172
206
|
],
|
|
173
207
|
"type": [
|
|
174
208
|
"tuple",
|
infra/terraform.tfstate.backup
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 4,
|
|
3
3
|
"terraform_version": "1.13.3",
|
|
4
|
-
"serial":
|
|
4
|
+
"serial": 23,
|
|
5
5
|
"lineage": "6cb48eaa-b069-089b-fce3-e277626defab",
|
|
6
6
|
"outputs": {
|
|
7
7
|
"bucket_name": {
|
|
@@ -62,6 +62,37 @@
|
|
|
62
62
|
}
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
"mode": "managed",
|
|
67
|
+
"type": "cloudflare_r2_custom_domain",
|
|
68
|
+
"name": "git",
|
|
69
|
+
"provider": "provider[\"registry.terraform.io/cloudflare/cloudflare\"]",
|
|
70
|
+
"instances": [
|
|
71
|
+
{
|
|
72
|
+
"schema_version": 500,
|
|
73
|
+
"attributes": {
|
|
74
|
+
"account_id": "dfdb8ca4e419990852eb214c5b50bd5e",
|
|
75
|
+
"bucket_name": "git",
|
|
76
|
+
"ciphers": null,
|
|
77
|
+
"domain": "git.pyrossh.dev",
|
|
78
|
+
"enabled": true,
|
|
79
|
+
"jurisdiction": "default",
|
|
80
|
+
"min_tls": null,
|
|
81
|
+
"status": {
|
|
82
|
+
"ownership": "pending",
|
|
83
|
+
"ssl": "initializing"
|
|
84
|
+
},
|
|
85
|
+
"zone_id": "e95a5d8957b75859c814579deebfce33",
|
|
86
|
+
"zone_name": "pyrossh.dev"
|
|
87
|
+
},
|
|
88
|
+
"sensitive_attributes": [],
|
|
89
|
+
"identity_schema_version": 0,
|
|
90
|
+
"dependencies": [
|
|
91
|
+
"cloudflare_r2_bucket.git"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
65
96
|
{
|
|
66
97
|
"mode": "managed",
|
|
67
98
|
"type": "cloudflare_r2_custom_domain",
|
|
@@ -102,12 +133,12 @@
|
|
|
102
133
|
{
|
|
103
134
|
"schema_version": 0,
|
|
104
135
|
"attributes": {
|
|
105
|
-
"id": "
|
|
136
|
+
"id": "06e5fdf0-4974-c673-b975-2f3fa99846fc",
|
|
106
137
|
"input": null,
|
|
107
138
|
"output": null,
|
|
108
139
|
"triggers_replace": {
|
|
109
140
|
"value": [
|
|
110
|
-
"2026-08-05T05:
|
|
141
|
+
"2026-08-05T05:36:25Z"
|
|
111
142
|
],
|
|
112
143
|
"type": [
|
|
113
144
|
"tuple",
|
|
@@ -132,12 +163,12 @@
|
|
|
132
163
|
"status": "tainted",
|
|
133
164
|
"schema_version": 0,
|
|
134
165
|
"attributes": {
|
|
135
|
-
"id": "
|
|
166
|
+
"id": "2036dc20-874b-06df-a0e0-481ee25c8d06",
|
|
136
167
|
"input": null,
|
|
137
168
|
"output": null,
|
|
138
169
|
"triggers_replace": {
|
|
139
170
|
"value": [
|
|
140
|
-
"2026-08-05T05:
|
|
171
|
+
"2026-08-05T05:36:38Z"
|
|
141
172
|
],
|
|
142
173
|
"type": [
|
|
143
174
|
"tuple",
|
package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "pyrossh-dev",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"scripts": {
|
|
5
|
-
"dev": "eleventy --serve",
|
|
5
|
+
"dev": "node --max-old-space-size=8192 ./node_modules/.bin/eleventy --serve",
|
|
6
6
|
"build": "node --max-old-space-size=8192 ./node_modules/.bin/eleventy",
|
|
7
7
|
"tf:plan": "terraform -chdir=infra plan",
|
|
8
8
|
"tf:apply": "terraform -chdir=infra apply"
|
src/_helpers/fileIcons.js
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
import iconSet from "@iconify-json/vscode-icons/icons.json" with { type: "json" };
|
|
2
2
|
|
|
3
|
+
// Chrome (confirmed in headless and in production) never paints a
|
|
4
|
+
// gradient-filled path that lives inside a <symbol> instantiated through
|
|
5
|
+
// <use> — the same markup renders fine as a standalone inline <svg>, so
|
|
6
|
+
// this is specific to the symbol/use indirection the sprite relies on.
|
|
7
|
+
// vscode-icons ships several file-type icons (rust, license, webp, python,
|
|
8
|
+
// kotlin, the "dist" folder) as gradients, so rather than special-case
|
|
9
|
+
// each one, every icon's gradients are resolved to one flat representative
|
|
10
|
+
// color at build time before being embedded in the sprite. Barely
|
|
11
|
+
// noticeable at the 16px size these render at, and keeps the one-symbol-
|
|
12
|
+
// shared-by-every-row sprite this module is built around (see
|
|
13
|
+
// iconSpriteDefs below) instead of duplicating full icon bodies per file.
|
|
14
|
+
const GRADIENT_TAG_RE = /<(linearGradient|radialGradient)\b([^>]*?)(?:\/>|>([\s\S]*?)<\/\1>)/g;
|
|
15
|
+
const STOP_COLOR_RE = /<stop\b[^>]*\bstop-color="([^"]+)"[^>]*\/?>/g;
|
|
16
|
+
const ATTR_RE = (attr) => new RegExp(`\\b${attr}="([^"]+)"`);
|
|
17
|
+
|
|
18
|
+
const flattenGradients = (body) => {
|
|
19
|
+
if (!body.includes("Gradient")) return body;
|
|
20
|
+
|
|
21
|
+
const gradients = new Map();
|
|
22
|
+
for (const match of body.matchAll(GRADIENT_TAG_RE)) {
|
|
23
|
+
const [, , attrs, inner] = match;
|
|
24
|
+
const id = attrs.match(ATTR_RE("id"))?.[1];
|
|
25
|
+
if (!id) continue;
|
|
26
|
+
const href = attrs.match(ATTR_RE("href"))?.[1]?.replace(/^#/, "");
|
|
27
|
+
const stops = inner ? [...inner.matchAll(STOP_COLOR_RE)].map((m) => m[1]) : [];
|
|
28
|
+
gradients.set(id, { href, stops });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const resolveColor = (id, seen = new Set()) => {
|
|
32
|
+
if (seen.has(id)) return null;
|
|
33
|
+
seen.add(id);
|
|
34
|
+
const g = gradients.get(id);
|
|
35
|
+
if (!g) return null;
|
|
36
|
+
if (g.stops.length) return g.stops[Math.floor(g.stops.length / 2)];
|
|
37
|
+
return g.href ? resolveColor(g.href, seen) : null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return body
|
|
41
|
+
.replace(GRADIENT_TAG_RE, "")
|
|
42
|
+
.replace(/(fill|stroke)="url\(#([^)]+)\)"/g, (whole, prop, id) => `${prop}="${resolveColor(id) ?? "#888"}"`);
|
|
43
|
+
};
|
|
44
|
+
|
|
3
45
|
// The old Astro version resolved per-extension file/folder icons from the
|
|
4
46
|
// full vscode-icons manifest (see git history at 7325531^:src/utils/files.ts).
|
|
5
47
|
// That manifest is itself a large VS Code extension repo installed as a git
|
|
@@ -89,7 +131,7 @@ export const iconSpriteDefs = () => {
|
|
|
89
131
|
const symbols = [...ICON_NAMES]
|
|
90
132
|
.map((name) => {
|
|
91
133
|
const icon = iconSet.icons[name];
|
|
92
|
-
return `<symbol id="icon-${name}" viewBox="0 0 ${iconSet.width} ${iconSet.height}">${icon.body}</symbol>`;
|
|
134
|
+
return `<symbol id="icon-${name}" viewBox="0 0 ${iconSet.width} ${iconSet.height}">${flattenGradients(icon.body)}</symbol>`;
|
|
93
135
|
})
|
|
94
136
|
.join("");
|
|
95
137
|
return `<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">${symbols}</svg>`;
|
src/_includes/layout.njk
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<meta property="og:description" content="{{ description or site.description }}" />
|
|
22
22
|
<meta property="og:image" content="/assets/icons/icon.svg" />
|
|
23
23
|
<meta name="twitter:card" content="summary_large_image" />
|
|
24
|
-
<script defer src="/assets/
|
|
24
|
+
<script defer src="/assets/client.js"></script>
|
|
25
25
|
<script src="/assets/vendor/htmx.min.js"></script>
|
|
26
26
|
</head>
|
|
27
27
|
<body>
|
src/_includes/repo-layout.njk
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<hr />
|
|
11
11
|
<div class="nav">
|
|
12
12
|
<div><a href="/repos/{{ repo }}/" hx-get="/repos/{{ repo }}/" hx-select="#repo-page" hx-target="#repo-page" hx-swap="outerHTML" hx-push-url="true" class="{% if tab == 'Readme' %}active-tab{% endif %}">Readme</a><span>|</span></div>
|
|
13
|
-
<div><a href="/repos/{{ repo }}/
|
|
14
|
-
<div><a href="/repos/{{ repo }}/
|
|
13
|
+
<div><a href="/repos/{{ repo }}/files/" hx-get="/repos/{{ repo }}/files/" hx-select="#repo-page" hx-target="#repo-page" hx-swap="outerHTML" hx-push-url="true" class="{% if tab == 'Files' %}active-tab{% endif %}">Code</a><span>|</span></div>
|
|
14
|
+
<div><a href="/repos/{{ repo }}/commits/" hx-get="/repos/{{ repo }}/commits/" hx-select="#repo-page" hx-target="#repo-page" hx-swap="outerHTML" hx-push-url="true" class="{% if tab == 'Commits' %}active-tab{% endif %}">Commits</a></div>
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
17
17
|
{% endmacro %}
|
src/repos/files-index.njk
CHANGED
|
@@ -6,7 +6,7 @@ pagination:
|
|
|
6
6
|
permalink: "/repos/{{ repo.id }}/files/"
|
|
7
7
|
layout: layout.njk
|
|
8
8
|
eleventyComputed:
|
|
9
|
-
title: "
|
|
9
|
+
title: "Code | {{ repo.data.title }}"
|
|
10
10
|
---
|
|
11
11
|
{% from "repo-layout.njk" import repoLayout %}
|
|
12
12
|
{% from "file-layout.njk" import fileLayout, fileContent %}
|