diff --git a/bun.lock b/bun.lock index 2848d4d..7c62e8d 100644 --- a/bun.lock +++ b/bun.lock @@ -5,14 +5,11 @@ "": { "name": "moshcode.sh", "dependencies": { - "@profullstack/footer": "latest", "express": "5.1.0", }, }, }, "packages": { - "@profullstack/footer": ["@profullstack/footer@0.2.1", "", { "peerDependencies": { "react": ">=18" }, "optionalPeers": ["react"], "bin": { "profullstack-footer": "bin/profullstack-footer.js" } }, "sha512-KHmKVwrlzCBrSAAJ4zobNFCxTg8VF0gvNMeAut00dX3+gbWCtk6eOwIR2AaqEC7smj6Aio6cIexzt/dUnv1McA=="], - "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], diff --git a/package.json b/package.json index 5f220ff..f04c06e 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "moshcode.sh", - "version": "0.1.0", + "version": "0.1.1", "private": true, - "description": "moshcode.sh \u2014 the home page for moshcode, a metal wrapper CLI for agentic coding", + "description": "moshcode.sh — the home page for moshcode, a metal wrapper CLI for agentic coding", "type": "module", "license": "MIT", "scripts": { @@ -13,7 +13,6 @@ "check": "bun scripts/sync-commands.mjs --check" }, "dependencies": { - "@profullstack/footer": "latest", "express": "5.1.0" }, "packageManager": "bun@1.4.0" diff --git a/public/style.css b/public/style.css index 530c51c..25a48e4 100644 --- a/public/style.css +++ b/public/style.css @@ -237,19 +237,12 @@ h1 { } /* ── footer ──────────────────────────────────────────────────────── */ -.foot { padding: 52px 0 44px; background: var(--bg-alt); border-top: 1px solid var(--line-soft); } -.foot-grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: 32px; } -.foot-brand .brand { font-size: 16px; margin: 0 0 10px; } -.creed { font-family: var(--mono); font-size: 12.5px; color: var(--lime-dim); margin: 0 0 12px; max-width: 34ch; } -.foot-brand .muted { font-size: 13.5px; margin: 0; } -.foot-col { display: flex; flex-direction: column; gap: 9px; } -.foot-head { font-family: var(--mono); font-size: 12px; letter-spacing: 0.08em; color: var(--muted); margin: 0 0 2px; text-transform: uppercase; } -.foot-col a { font-size: 14px; color: var(--ink-2); text-decoration: none; } -.foot-col a:hover { color: var(--lime); } -.webring { display: flex; gap: 10px; margin: 12px 0 0; font-family: var(--mono); font-size: 12.5px; } -.webring a { color: var(--muted); text-decoration: none; } -.webring a:hover { color: var(--lime); } -@media (max-width: 760px) { .foot-grid { grid-template-columns: 1fr 1fr; } } +.foot { padding: 22px 0; background: var(--bg-alt); border-top: 1px solid var(--line-soft); } +.foot-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px; } +.foot-row .brand { font-size: 14px; margin: 0; } +.foot-row nav { display: flex; flex-wrap: wrap; gap: 6px 18px; } +.foot-row nav a { font-size: 14px; color: var(--ink-2); text-decoration: none; } +.foot-row nav a:hover { color: var(--lime); } /* ── blog ────────────────────────────────────────────────────────── */ .post-list { display: grid; gap: 26px; max-width: 760px; } @@ -277,7 +270,7 @@ h1 { .prose .term { margin: 26px 0 28px; } @media (min-width: 900px) { .prose .term-wide { width: calc(100% + 160px); max-width: none; } } -/* CrawlProof text_link frame above the footer: fluid, 40px, carries its own +/* CrawlProof text_link frame at the top of the content: fluid, 40px, carries its own "Sponsored" mark. */ -.cp-ad { margin-top: 40px; margin-bottom: 40px; } +.cp-ad { margin-top: 24px; margin-bottom: 24px; } .cp-ad iframe { display: block; width: 100%; height: 40px; border: 0; } diff --git a/src/content.mjs b/src/content.mjs index d6bb539..5d38296 100644 --- a/src/content.mjs +++ b/src/content.mjs @@ -265,33 +265,9 @@ while (alive) { ]; export const FOOTER_LINKS = [ - { - heading: 'moshcode', - links: [ - { label: 'GitHub', href: 'https://github.com/moshcoder/moshcode' }, - { label: 'Commands', href: '/commands' }, - { label: 'Blog', href: '/blog' }, - { label: 'Install script', href: '/install.sh' }, - { label: 'For agents (llms.txt)', href: '/llms.txt' }, - ], - }, - { - heading: 'the Pit', - links: [ - { label: 'Moshpit Manager', href: 'https://app.moshcode.sh/pit' }, - { label: 'pit.moshcode.sh', href: 'https://pit.moshcode.sh' }, - { label: 'app.moshcode.sh', href: 'https://app.moshcode.sh' }, - { label: 'Moshpit DNS', href: 'https://dns.moshcode.sh/dns-query' }, - { label: 'moshcoding.com', href: 'https://moshcoding.com' }, - ], - }, - { - heading: 'elsewhere', - links: [ - { label: 'X / chovy', href: 'https://x.com/chovy' }, - { label: 'Bluesky', href: 'https://bsky.app/profile/moshcoding.bsky.social' }, - { label: 'YouTube', href: 'https://youtube.com/@moshcoding' }, - { label: 'Twitch', href: 'https://www.twitch.tv/chovyo' }, - ], - }, + { label: 'GitHub', href: 'https://github.com/moshcoder/moshcode' }, + { label: 'Commands', href: '/commands' }, + { label: 'Blog', href: '/blog' }, + { label: 'install.sh', href: '/install.sh' }, + { label: 'llms.txt', href: '/llms.txt' }, ]; diff --git a/src/server.mjs b/src/server.mjs index a7b8e7e..645265a 100644 --- a/src/server.mjs +++ b/src/server.mjs @@ -1,6 +1,5 @@ import express from 'express'; import { randomBytes } from 'node:crypto'; -import { footerHtml } from '@profullstack/footer'; import { readFileSync } from 'node:fs'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -27,13 +26,40 @@ const PAGES = [ { path: '/blog', changefreq: 'weekly', priority: '0.8' }, ]; +const PIT_FOOTER_URL = 'https://pit.world/snippets/footer.html?site=moshcode.sh'; +const PIT_FOOTER_TTL_MS = 60 * 60 * 1000; +const pitCache = { html: '', fetchedAt: 0, pending: null }; + +async function refreshPitFooter() { + try { + const res = await fetch(PIT_FOOTER_URL, { signal: AbortSignal.timeout(3000) }); + if (!res.ok) return; + const html = await res.text(); + if (html.includes('data-pit-footer')) pitCache.html = html; + } catch { + // keep the last good copy + } finally { + pitCache.fetchedAt = Date.now(); + pitCache.pending = null; + } +} + +async function pitFooter() { + if (Date.now() - pitCache.fetchedAt > PIT_FOOTER_TTL_MS) { + pitCache.pending ??= refreshPitFooter(); + // Only the very first render waits (bounded by the 3 s timeout). + if (!pitCache.html) await pitCache.pending; + } + return pitCache.html; +} + export function createApp() { const app = express(); app.disable('x-powered-by'); app.set('etag', 'strong'); app.use((_req, res, next) => { - // Per-response nonce for the one inline