Compare commits
No commits in common. "ebecb26c7c59c9f9879ab02432a582606072ee8a" and "c1fefcc766388420975fd0f4ea3cf77736df74e5" have entirely different histories.
ebecb26c7c
...
c1fefcc766
13 changed files with 65 additions and 148 deletions
|
|
@ -11,8 +11,6 @@ Environment=TZ=Europe/Zurich
|
||||||
Environment=ADMIN_LOG=%h/src/koopa/koopa-admin-log
|
Environment=ADMIN_LOG=%h/src/koopa/koopa-admin-log
|
||||||
# Override on koopa if the tdpd checkout path differs
|
# Override on koopa if the tdpd checkout path differs
|
||||||
Environment=TDPD_ROOT=%h/git/src/ngi/tech-dossier-project-data
|
Environment=TDPD_ROOT=%h/git/src/ngi/tech-dossier-project-data
|
||||||
# Live site root (timer must refresh public JSON, not only the kal tree)
|
|
||||||
Environment=OUT=/var/www/monitoring-sites/dossiers.ngi.hacktivism.ch/branch-status.json
|
|
||||||
EnvironmentFile=-%h/.config/dossiers-ngi/branch-status.env
|
EnvironmentFile=-%h/.config/dossiers-ngi/branch-status.env
|
||||||
ExecStart=/usr/bin/python3 %h/src/koopa/koopa-admin-log/scripts/dossiers-ngi/branch-status-hourly.py
|
ExecStart=/usr/bin/python3 %h/src/koopa/koopa-admin-log/scripts/dossiers-ngi/branch-status-hourly.py
|
||||||
SuccessExitStatus=0 1
|
SuccessExitStatus=0 1
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@ SoT for the blank cascade landing on **dossiers.ngi.hacktivism.ch**
|
||||||
| Var | Default | Meaning |
|
| Var | Default | Meaning |
|
||||||
|-----|---------|---------|
|
|-----|---------|---------|
|
||||||
| `TDPD_ROOT` | `$HOME/git/src/ngi/tech-dossier-project-data` | tech-dossier-project-data checkout for tip SHAs |
|
| `TDPD_ROOT` | `$HOME/git/src/ngi/tech-dossier-project-data` | tech-dossier-project-data checkout for tip SHAs |
|
||||||
| `OUT` | `sites/dossiers.ngi.hacktivism.ch/branch-status.json` under kal | write path for JSON (live www on koopa) |
|
|
||||||
| `ADMIN_LOG` | (script derives from `__file__`) | koopa-admin-log root |
|
| `ADMIN_LOG` | (script derives from `__file__`) | koopa-admin-log root |
|
||||||
|
|
||||||
On koopa the clone often lives at `%h/src/koopa/koopa-admin-log`; set
|
On koopa the clone often lives at `%h/src/koopa/koopa-admin-log`; set
|
||||||
`TDPD_ROOT` and `OUT` in `~/.config/dossiers-ngi/branch-status.env` when the
|
`TDPD_ROOT` in the service `Environment=` if the tdpd path differs.
|
||||||
tdpd path or live www path differs from the laptop defaults.
|
|
||||||
|
|
||||||
## Manual run
|
## Manual run
|
||||||
|
|
||||||
|
|
@ -42,47 +40,3 @@ Hourly JSON can sit next to the HTML once the timer is installed on koopa
|
||||||
|
|
||||||
Hourly builder belongs in **kal** (this tree). Do **not** put
|
Hourly builder belongs in **kal** (this tree). Do **not** put
|
||||||
`scripts/branch-status-hourly.py` back into tdpd.
|
`scripts/branch-status-hourly.py` back into tdpd.
|
||||||
|
|
||||||
## Sticky cascade bar
|
|
||||||
|
|
||||||
Stock Caddy `templates` renders `{% include "_cascade/bar.html" . %}` on each
|
|
||||||
HTML page. The include path has no leading slash. The dot passes the request,
|
|
||||||
so `.Req.URL.Path` marks the active link with `class="is-active"` and
|
|
||||||
`aria-current="page"`. Delimiters are `{%` `%}`, so a later `{{ }}` in real
|
|
||||||
dossier HTML stays literal.
|
|
||||||
|
|
||||||
The bar lists cascade `/` plus the five branch paths. Seeded tips match
|
|
||||||
`branch-status.json`. `/_cascade/bar.js` refreshes `[data-tip]` from that JSON
|
|
||||||
(`cache: no-store`). CSS is `/_cascade/bar.css` (`position: sticky`).
|
|
||||||
|
|
||||||
Enable templates before rsync. A page without the include does not grow the
|
|
||||||
bar. `{%` without the templates directive is shown as raw text.
|
|
||||||
|
|
||||||
Templates apply is **host-local on koopa** (`~/bin/apply-dossiers-ngi-templates.sh`),
|
|
||||||
not tracked in this repo. It edits `~/koopa-caddy/Caddyfile` only (this host;
|
|
||||||
keeps `header Alt-Svc "clear"` and any `basic_auth`; leaves `.2` / `.3`
|
|
||||||
untouched). Then reload with the usual home→`/etc` helper:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash ~/bin/apply-dossiers-ngi-templates.sh
|
|
||||||
sudo ~/bin/caddy-apply
|
|
||||||
```
|
|
||||||
|
|
||||||
The stanza body for hand-check / re-seed lives in
|
|
||||||
`scripts/dossiers-ngi/caddy-dossiers-ngi.snippet`.
|
|
||||||
`scripts/caddy/caddy-apply.sh --snippet` leaves an existing block unchanged.
|
|
||||||
Leave `scripts/caddy/apply-goa-wdGet-full-replace.sh` and
|
|
||||||
`scripts/caddy/apply-dossiers-ngi-basicauth.sh` unused. No response-body
|
|
||||||
replace plugin.
|
|
||||||
|
|
||||||
After validate and reload succeed, rsync from the laptop (Freigabe):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rsync -avz --delete --exclude .DS_Store \
|
|
||||||
"$HOME/git/admin-logs/local/koopa-admin-log/sites/dossiers.ngi.hacktivism.ch/" \
|
|
||||||
hernani@koopa:/var/www/monitoring-sites/dossiers.ngi.hacktivism.ch/
|
|
||||||
```
|
|
||||||
|
|
||||||
`--delete` removes `_cascade/` on the server when the source tree is an older
|
|
||||||
copy. The bar does not finish the dossier site. This section does not install
|
|
||||||
the hourly timer.
|
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,9 @@ from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
ADMIN_LOG = Path(__file__).resolve().parents[2]
|
ADMIN_LOG = Path(__file__).resolve().parents[2]
|
||||||
_DEFAULT_OUT = ADMIN_LOG / "sites" / "dossiers.ngi.hacktivism.ch" / "branch-status.json"
|
OUT = ADMIN_LOG / "sites" / "dossiers.ngi.hacktivism.ch" / "branch-status.json"
|
||||||
HOST = "https://dossiers.ngi.hacktivism.ch"
|
HOST = "https://dossiers.ngi.hacktivism.ch"
|
||||||
|
|
||||||
|
|
||||||
def out_path() -> Path:
|
|
||||||
raw = os.environ.get("OUT", "").strip()
|
|
||||||
return Path(raw).expanduser() if raw else _DEFAULT_OUT
|
|
||||||
|
|
||||||
# Default local clone; override with TDPD_ROOT (koopa may use a different path).
|
# Default local clone; override with TDPD_ROOT (koopa may use a different path).
|
||||||
DEFAULT_TDPD = Path.home() / "git" / "src" / "ngi" / "tech-dossier-project-data"
|
DEFAULT_TDPD = Path.home() / "git" / "src" / "ngi" / "tech-dossier-project-data"
|
||||||
|
|
||||||
|
|
@ -81,10 +76,9 @@ def main() -> int:
|
||||||
for b in branches
|
for b in branches
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
dest = out_path()
|
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
OUT.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
||||||
dest.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
print(f"wrote {OUT}", file=sys.stderr)
|
||||||
print(f"wrote {dest}", file=sys.stderr)
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# Stanza body for dossiers.ngi.hacktivism.ch only (hand-check / re-seed).
|
|
||||||
# Templates apply is host-local on koopa (not in this repo):
|
|
||||||
# bash ~/bin/apply-dossiers-ngi-templates.sh
|
|
||||||
# sudo ~/bin/caddy-apply
|
|
||||||
#
|
|
||||||
# Keep the existing line: header Alt-Svc "clear"
|
|
||||||
# Keep any existing basic_auth in that same block.
|
|
||||||
# scripts/caddy/caddy-apply.sh --snippet reports an existing block and
|
|
||||||
# does not merge these lines. Leave that script unused for this change.
|
|
||||||
# Leave scripts/caddy/apply-goa-wdGet-full-replace.sh unused.
|
|
||||||
# Leave scripts/caddy/apply-dossiers-ngi-basicauth.sh unused.
|
|
||||||
# Stock Caddy templates only. No replace-response plugin.
|
|
||||||
#
|
|
||||||
# Tab-indented lines inserted after header Alt-Svc:
|
|
||||||
|
|
||||||
templates {
|
|
||||||
mime text/html
|
|
||||||
between "{%" "%}"
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
.cascade-bar {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 10;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.35rem 0.85rem;
|
|
||||||
align-items: baseline;
|
|
||||||
margin: -1.5rem -1.5rem 1rem;
|
|
||||||
padding: 0.55rem 1.5rem;
|
|
||||||
background: #10141a;
|
|
||||||
border-bottom: 1px solid #243040;
|
|
||||||
}
|
|
||||||
.cascade-bar a {
|
|
||||||
color: #7ec8ff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.cascade-bar a:hover { text-decoration: underline; }
|
|
||||||
.cascade-bar a.is-active {
|
|
||||||
color: #e8eef4;
|
|
||||||
text-decoration: none;
|
|
||||||
box-shadow: inset 0 -2px 0 #e8eef4;
|
|
||||||
}
|
|
||||||
.cascade-bar a.is-active:hover { text-decoration: none; }
|
|
||||||
.cascade-bar code { color: inherit; }
|
|
||||||
.cascade-bar .tip {
|
|
||||||
color: #8a96a3;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{% $p := .Req.URL.Path %}
|
|
||||||
<link rel="stylesheet" href="/_cascade/bar.css">
|
|
||||||
<nav class="cascade-bar" aria-label="cascade">
|
|
||||||
<a href="/" {% if or (eq $p "/") (eq $p "/index.html") %}class="is-active" aria-current="page"{% end %}>cascade</a>
|
|
||||||
<a href="/main/" {% if or (eq $p "/main") (or (eq $p "/main/") (eq $p "/main/index.html")) %}class="is-active" aria-current="page"{% end %}><code>/main/</code> <span class="tip" data-tip="main">main @ d2fbd79</span></a>
|
|
||||||
<a href="/feat-sm-content/" {% if or (eq $p "/feat-sm-content") (or (eq $p "/feat-sm-content/") (eq $p "/feat-sm-content/index.html")) %}class="is-active" aria-current="page"{% end %}><code>/feat-sm-content/</code> <span class="tip" data-tip="feat/sm-content">feat/sm-content @ 089ef1f</span></a>
|
|
||||||
<a href="/feat-website-features/" {% if or (eq $p "/feat-website-features") (or (eq $p "/feat-website-features/") (eq $p "/feat-website-features/index.html")) %}class="is-active" aria-current="page"{% end %}><code>/feat-website-features/</code> <span class="tip" data-tip="feat/website-features">feat/website-features @ 53a3176</span></a>
|
|
||||||
<a href="/feat-website-design/" {% if or (eq $p "/feat-website-design") (or (eq $p "/feat-website-design/") (eq $p "/feat-website-design/index.html")) %}class="is-active" aria-current="page"{% end %}><code>/feat-website-design/</code> <span class="tip" data-tip="feat/website-design">feat/website-design @ 2e26c80</span></a>
|
|
||||||
<a href="/feat-website-views/" {% if or (eq $p "/feat-website-views") (or (eq $p "/feat-website-views/") (eq $p "/feat-website-views/index.html")) %}class="is-active" aria-current="page"{% end %}><code>/feat-website-views/</code> <span class="tip" data-tip="feat/website-views">feat/website-views @ bbafc38</span></a>
|
|
||||||
</nav>
|
|
||||||
<script src="/_cascade/bar.js" defer></script>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
(function () {
|
|
||||||
var nodes = document.querySelectorAll(".cascade-bar [data-tip]");
|
|
||||||
if (!nodes.length) return;
|
|
||||||
fetch("/branch-status.json", { cache: "no-store" })
|
|
||||||
.then(function (res) {
|
|
||||||
if (!res.ok) throw new Error("status");
|
|
||||||
return res.json();
|
|
||||||
})
|
|
||||||
.then(function (data) {
|
|
||||||
var tips = {};
|
|
||||||
var list = (data && data.branches) || [];
|
|
||||||
for (var i = 0; i < list.length; i++) {
|
|
||||||
var row = list[i];
|
|
||||||
if (row && row.branch && row.tip) tips[row.branch] = row.tip;
|
|
||||||
}
|
|
||||||
for (var j = 0; j < nodes.length; j++) {
|
|
||||||
var el = nodes[j];
|
|
||||||
var name = el.getAttribute("data-tip");
|
|
||||||
var tip = tips[name];
|
|
||||||
if (tip) el.textContent = name + " @ " + tip;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function () {});
|
|
||||||
})();
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,8 +26,15 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1><code>/feat-sm-content/</code></h1>
|
<h1><code>/feat-sm-content/</code></h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/sm-content</code> @ <code>089ef1f</code></p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/sm-content</code> @ <code>089ef1f</code></p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,8 +26,15 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1><code>/feat-website-design/</code></h1>
|
<h1><code>/feat-website-design/</code></h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-design</code> @ <code>2e26c80</code></p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-design</code> @ <code>2e26c80</code></p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,8 +26,15 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1><code>/feat-website-features/</code></h1>
|
<h1><code>/feat-website-features/</code></h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-features</code> @ <code>53a3176</code></p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-features</code> @ <code>53a3176</code></p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,8 +26,15 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1><code>/feat-website-views/</code></h1>
|
<h1><code>/feat-website-views/</code></h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-views</code> @ <code>bbafc38</code></p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>feat/website-views</code> @ <code>bbafc38</code></p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,9 +26,16 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1>cascade</h1>
|
<h1>cascade</h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00</p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00</p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
<ul class="plain">
|
<ul class="plain">
|
||||||
<li><a href="/main/"><code>/main/</code></a> <span class="dim">·</span> <code>main</code> @ <code>d2fbd79</code></li>
|
<li><a href="/main/"><code>/main/</code></a> <span class="dim">·</span> <code>main</code> @ <code>d2fbd79</code></li>
|
||||||
<li><a href="/feat-sm-content/"><code>/feat-sm-content/</code></a> <span class="dim">·</span> <code>feat/sm-content</code> @ <code>089ef1f</code></li>
|
<li><a href="/feat-sm-content/"><code>/feat-sm-content/</code></a> <span class="dim">·</span> <code>feat/sm-content</code> @ <code>089ef1f</code></li>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ a { color: #7ec8ff; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
h1 { font-size: 1.15rem; font-weight: 600; margin: 0 0 0.5rem; color: #e8eef4; }
|
||||||
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
.meta { color: #8a96a3; margin: 0 0 1rem; }
|
||||||
|
.nav { margin: 0.5rem 0 1rem; }
|
||||||
|
.nav a { margin-right: 0.85rem; }
|
||||||
ul.plain { padding-left: 1.2rem; margin: 0; }
|
ul.plain { padding-left: 1.2rem; margin: 0; }
|
||||||
li { margin: 0.25rem 0; }
|
li { margin: 0.25rem 0; }
|
||||||
.dim { color: #6a7682; }
|
.dim { color: #6a7682; }
|
||||||
|
|
@ -24,8 +26,15 @@ li { margin: 0.25rem 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "_cascade/bar.html" . %}
|
|
||||||
<h1><code>/main/</code></h1>
|
<h1><code>/main/</code></h1>
|
||||||
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>main</code> @ <code>d2fbd79</code></p>
|
<p class="meta">last-built: 2026-09-30T02:30:50+02:00 <span class="dim">·</span> <code>main</code> @ <code>d2fbd79</code></p>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="/">/</a>
|
||||||
|
<a href="/main/">/main/</a>
|
||||||
|
<a href="/feat-sm-content/">/feat-sm-content/</a>
|
||||||
|
<a href="/feat-website-features/">/feat-website-features/</a>
|
||||||
|
<a href="/feat-website-design/">/feat-website-design/</a>
|
||||||
|
<a href="/feat-website-views/">/feat-website-views/</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue