Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
"dependencies": {
"@profullstack/auth-system": "^0.8.3",
"@profullstack/emailer": "^1.0.3",
"@profullstack/footer": "latest",
"@profullstack/hqtui": "^0.10.3",
"@profullstack/player": "^0.14.0",
"jsonwebtoken": "^9.0.2",
Expand Down
46 changes: 33 additions & 13 deletions src/server/footer.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
// The shared Profullstack footer (@profullstack/footer), rendered into the
// <!--pfs-footer--> markers of index.html from the @latest template on jsDelivr
// (cached an hour by the package; the bundled template if the CDN is down), so a
// footer release needs no redeploy and the ring's verifier sees it in the HTML.
import { footerHtml } from '@profullstack/footer';
// The pit.world network footer, fetched server side from
// https://pit.world/snippets/footer.html and rendered into the
// <!--pit-footer--> markers of index.html on every page load. It refetches at
// most hourly with a 3-second timeout; on failure it keeps the last good copy,
// or renders nothing, so pit.world being down never breaks the page.
const URL_ = 'https://pit.world/snippets/footer.html?site=hdtilt.com';
const TTL = 60 * 60 * 1000;
const REGION = /<!--pit-footer-->[\s\S]*?<!--\/pit-footer-->/;

const OPTIONS = { site: 'https://hdtilt.com/' };
const REGION = /<!--pfs-footer-->[\s\S]*?<!--\/pfs-footer-->/;
let cached = '';
let fetchedAt = 0;
/** @type {Promise<void> | null} */
let inflight = null;

function refresh() {
if (Date.now() - fetchedAt < TTL) return Promise.resolve();
inflight ??= (async () => {
try {
const res = await fetch(URL_, { signal: AbortSignal.timeout(3000) });
if (res.ok) {
const html = await res.text();
if (html.includes('data-pit-footer')) cached = html;
}
} catch {
// Keep the last good footer.
} finally {
fetchedAt = Date.now();
inflight = null;
}
})();
return inflight;
}

/** @param {string} html */
export async function withFooter(html) {
if (!REGION.test(html)) return html;
try {
const footer = await footerHtml(OPTIONS);
return html.replace(REGION, () => `<!--pfs-footer-->${footer}<!--/pfs-footer-->`);
} catch {
return html;
}
await refresh();
return html.replace(REGION, () => `<!--pit-footer-->${cached}<!--/pit-footer-->`);
}
28 changes: 23 additions & 5 deletions web/public/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,8 @@ body.gated .nav-items button:not(#nav-account) {
min-width: 0;
}

/* @profullstack/footer: only while the sheet is up, docked under it. */
/* Footer (own copyright row + the pit.world network footer): only while the
sheet is up, docked under it. */
.ring-dock {
display: none;
}
Expand All @@ -1101,6 +1102,27 @@ body.gated .nav-items button:not(#nav-account) {
display: block;
color: var(--text);
}
.site-foot {
margin: 0;
padding: 0.75rem 1rem 0;
text-align: center;
font-size: 0.85rem;
color: var(--dim);
}
.site-foot a {
color: inherit;
}
/* The pit.world snippet is styled for light pages; this app is always dark. */
.ring-dock .pit-foot {
color: var(--dim);
}
.ring-dock .pit-foot b {
color: var(--text);
}
.ring-dock .pit-foot-links > a,
.ring-dock .pit-foot-links > button {
color: var(--accent);
}
/* CrawlProof ad unit, docked at the top of the sheet (under the nav): zero
height until ad.js fills it, and never on the sign-in / account screens.
Filled only from mountAd() in app.js, the first time a home or settings
Expand Down Expand Up @@ -1136,10 +1158,6 @@ body.nav-on #sheet:not([hidden]) ~ .ad-dock {
#sheet:not([hidden]):not([data-screen="account"]):has(~ .ad-dock .cp-ad[data-cp-filled]) {
padding-top: 4rem;
}
.ring-dock .pfs-footer {
--pfs-footer-muted: var(--dim);
border-top: 0;
}

/* ---- Movies & Shows ---------------------------------------------------------- */
.list.vod {
Expand Down
7 changes: 3 additions & 4 deletions web/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,9 @@
the footer, never over the picture or on sign-in). -->
<div class="ad-dock"><aside id="cp-ad" class="cp-ad" data-cp-ad></aside></div>

<!-- @profullstack/footer (copyright + Profullstack webring), shown under the
setup/settings sheet, never over the picture. The server renders it between
the markers from the current @latest template on every page load. -->
<div class="ring-dock"><!--pfs-footer--><!--/pfs-footer--></div>
<!-- Footer, shown under the setup/settings sheet, never over the picture. The
server renders the pit.world network footer between the markers. -->
<div class="ring-dock"><p class="site-foot">&copy; 2026 Profullstack, Inc. &middot; <a href="https://github.com/profullstack/hdtilt.com">Source</a></p><!--pit-footer--><!--/pit-footer--></div>
</div>
<script type="module" src="/app.js"></script>
<script src="https://crawlproof.com/ad.js" async></script>
Expand Down
Loading