Adds live pages for each repo without leaving hephaestus.x:
hephaestus.x/silentmode/ → index of all silentmode/* repos
hephaestus.x/silentmode/theseus/ → README + recent commits + clone URLs
hephaestus.x/silentmode/sirius/ → same
hephaestus.x/silentmode/ariadne/ → same, gated ("private, sign in to browse")
hephaestus.x/silentmode/hephaestus/ → same, gated
Single _template.html hardcoded per repo via sed; each detail page pulls
metadata + README + last 8 commits from code.silentmode.st via the
CORS-enabled Forgejo API on load, renders README with a minimal
markdown-to-HTML pass, and gracefully falls back to a "sign in to browse"
note when the API returns 401/404 (private repo).
The URL stays on hephaestus.x while browsing — user only leaves when they
click "Browse full source →" or a specific commit link.
127 lines
5.3 KiB
HTML
127 lines
5.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>silentmode/* — Hephaestus</title>
|
|
<meta name="description" content="All silentmode/* repos on Hephaestus.">
|
|
<style>
|
|
:root{
|
|
--bg:#0b0e14; --panel:#141a24; --panel2:#18202c; --line:rgba(255,255,255,.09);
|
|
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d;
|
|
}
|
|
*{box-sizing:border-box}
|
|
body{margin:0;background:radial-gradient(1100px 560px at 50% -12%,#16202e,var(--bg));
|
|
color:var(--ink);font:16px/1.65 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;min-height:100vh;
|
|
display:flex;flex-direction:column}
|
|
a{color:var(--acid);text-decoration:none}
|
|
a:hover{text-decoration:underline}
|
|
.wrap{max-width:820px;margin:0 auto;padding:0 1.2rem;width:100%;flex:1}
|
|
.top{padding:1.6rem 0;color:var(--dim);font-size:13px}
|
|
.top a{color:var(--mut)}
|
|
header.hero{text-align:center;padding:3rem 1.2rem 1rem}
|
|
.mark{font-size:52px;line-height:1}
|
|
h1{font-size:clamp(1.8rem,4.5vw,2.4rem);margin:.4rem 0 .3rem;letter-spacing:-0.01em;font-family:ui-monospace,monospace;font-weight:500}
|
|
h1 .g{color:var(--acid)}
|
|
.tag{color:var(--mut);font-size:1rem;max-width:560px;margin:0 auto}
|
|
section{padding:2rem 0 1rem}
|
|
.repo{display:grid;grid-template-columns:1fr auto;gap:16px;align-items:baseline;
|
|
background:var(--panel);border:1px solid var(--line);border-radius:12px;
|
|
padding:16px 20px;margin-bottom:10px;transition:border-color .1s,background .1s;text-decoration:none}
|
|
.repo:hover{border-color:var(--acid);background:var(--panel2);text-decoration:none}
|
|
.repo .name{font-family:ui-monospace,monospace;font-size:14.5px;color:var(--ink)}
|
|
.repo .name .owner{color:var(--dim)}
|
|
.repo .name .sep{color:var(--dim);margin:0 2px}
|
|
.repo .name .repo-label{color:var(--acid)}
|
|
.repo .desc{color:var(--mut);font-size:13.5px;line-height:1.5;margin:.3rem 0 0;grid-column:1/-1}
|
|
.repo .meta{color:var(--dim);font-size:12px;font-family:ui-monospace,monospace;text-align:right;white-space:nowrap}
|
|
.repo.priv .name .repo-label{color:var(--mut)}
|
|
.empty{color:var(--dim);font-size:14px;text-align:center;padding:2rem}
|
|
footer{border-top:1px solid var(--line);padding:2rem 1.2rem 3rem;color:var(--dim);font-size:13px;text-align:center;margin-top:2rem}
|
|
footer a{color:var(--mut)} footer a:hover{color:var(--ink)}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="wrap">
|
|
|
|
<div class="top">
|
|
<a href="../">hephaestus.x</a> / <strong>silentmode</strong>
|
|
</div>
|
|
|
|
<header class="hero">
|
|
<div class="mark">🛠</div>
|
|
<h1><span class="g">silentmode</span>/*</h1>
|
|
<p class="tag">Public repositories under the <code>silentmode</code> org. Click through for a per-repo overview or straight into the full forge.</p>
|
|
</header>
|
|
|
|
<section>
|
|
<div id="repos"><div class="empty">Loading from the forge…</div></div>
|
|
</section>
|
|
|
|
</div>
|
|
|
|
<footer>
|
|
<a href="../">hephaestus.x</a> · Silent Mode's decentralized code host
|
|
</footer>
|
|
|
|
<script type="module">
|
|
// Static index: enumerate the known silentmode/* repos. Public ones link to the
|
|
// per-repo detail page we generate at hephaestus.x/silentmode/<name>/ ; private
|
|
// ones link straight to code.silentmode.st since the detail page shows a
|
|
// "sign in to browse" message anyway.
|
|
const KNOWN = [
|
|
{name: "theseus", private: false},
|
|
{name: "sirius", private: false},
|
|
{name: "ariadne", private: true},
|
|
{name: "hephaestus", private: true},
|
|
];
|
|
const container = document.getElementById("repos");
|
|
|
|
function esc(s) {
|
|
return String(s ?? "").replace(/[&<>"']/g, c => ({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));
|
|
}
|
|
function fmtDate(iso) {
|
|
if (!iso) return "";
|
|
const d = new Date(iso);
|
|
if (isNaN(d)) return "";
|
|
const days = (Date.now() - d.getTime()) / 86400000;
|
|
if (days < 1) return "today";
|
|
if (days < 30) return `${Math.round(days)}d ago`;
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
async function loadRepo(entry) {
|
|
const priv = entry.private;
|
|
// Public repos: fetch fresh info via CORS. Private: fill in a static line.
|
|
if (!priv) {
|
|
try {
|
|
const info = await fetch(`https://code.silentmode.st/api/v1/repos/silentmode/${entry.name}`).then(r => r.json());
|
|
return {...entry, description: info.description, updated_at: info.updated_at, size: info.size};
|
|
} catch { return entry; }
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
Promise.all(KNOWN.map(loadRepo)).then(list => {
|
|
container.innerHTML = list.map(r => {
|
|
// Public → per-repo detail page on hephaestus.x; private → direct to code.silentmode.st
|
|
const href = r.private
|
|
? `https://code.silentmode.st/silentmode/${r.name}`
|
|
: `./${r.name}/`;
|
|
const badge = r.private ? '<span style="color:var(--dim)">private</span>' : "";
|
|
const updated = r.updated_at ? `updated ${fmtDate(r.updated_at)}` : "";
|
|
const desc = r.description ? `<div class="desc">${esc(r.description)}</div>` : "";
|
|
return `
|
|
<a class="repo${r.private ? " priv" : ""}" href="${href}">
|
|
<div class="name">
|
|
<span class="owner">silentmode</span><span class="sep">/</span><span class="repo-label">${esc(r.name)}</span>
|
|
${desc}
|
|
</div>
|
|
<div class="meta">${badge}${badge && updated ? " · " : ""}${updated}</div>
|
|
</a>`;
|
|
}).join("");
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|