Bulk-inserts <link rel="icon" type="image/svg+xml" href="/favicon.svg"> before the </head> tag on every silentmode.st page that was missing it. All 36 site HTML pages now advertise the chain-links favicon; browsers show it in tabs and bookmarks across the whole umbrella site. Pages touched (29): apps/, choose/*, deviant/* (7 pages under the parent house), hephaestus/, hephaestus.x/* (9 chain-published mirror pages), nav/ (redirect stub), register.html (redirect stub), sirius/, sirius/register.html, store/ (redirect stub), tlds/. Already had favicon from earlier passes (7): index.html, brand/, tools/, prometheus/, helios/, hermes/, releases/. Line-ending preservation: choose/index.html and sirius/register.html were originally stored with CRLF endings; the plain Python read/write path normalized them to LF and produced a noisy diff. Both files re-serialized as CRLF before the favicon insert to keep the diff to +1 line each. Deploy: rsync-equivalent tar-pipe to /opt/silent-mode/site/, plus per-file scp for the two CRLF-corrected files. Verified live: 7 spot-checked URLs each report exactly one <link rel="icon"> in served HTML.
128 lines
5.4 KiB
HTML
128 lines
5.4 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>
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
</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>
|