radical/footer.js
King Omar 2afb56d93d footer: add slim single-line mode for fixed-height app shells
Full block footer steals ~230px in fixed app layouts (iamthelaw et al).
New data-mode="slim" renders a compact accent-matched one-line bar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 17:48:26 +10:00

154 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ═══════════════════════════════════════════════════════════════════════
The Radical Party — shared footer / wayfinding component.
ONE script, loaded on every subdomain, so no island is a dead end:
<script src="https://theradicalparty.com/footer.js" defer></script>
- Self-contained: injects itself into <body>, styles live in a Shadow DOM
so nothing leaks in or out of the host page's CSS.
- Central: edit this one file, every site updates. No per-repo redeploy.
- Three modes, chosen via a data attribute on the script tag:
(default) full footer bar at the end of the page.
data-mode="slim" compact single-line bar (~40px) — for fixed-height
app shells where the full block would steal layout.
data-mode="pill" compact fixed corner badge — for full-screen apps
(maps, games) where a block footer would be hidden.
Optional: data-accent="#ff0099" to match a site's own accent.
═══════════════════════════════════════════════════════════════════════ */
(function () {
if (window.__radicalFooter) return;
window.__radicalFooter = 1;
// Read config off our own <script> tag (currentScript is null under defer).
var self =
document.currentScript ||
document.querySelector('script[src*="footer.js"]');
var ds = (self && self.dataset) || {};
var mode =
ds.mode === 'pill' ? 'pill' : ds.mode === 'slim' ? 'slim' : 'bar';
var accent = ds.accent || '#ff2d55';
var here = location.hostname; // don't link a site back to itself
// Wayfinding + a curated set of mission-aligned flagships (not all 25).
var HOME = 'https://theradicalparty.com';
var HUB = 'https://links.theradicalparty.com';
var FLAGSHIPS = [
['Ghost', 'https://ghost.theradicalparty.com'],
['Watermelon', 'https://watermelon.theradicalparty.com'],
['Search', 'https://search.theradicalparty.com'],
['Cipher', 'https://cipher.theradicalparty.com'],
['I Am the Law', 'https://iamthelaw.theradicalparty.com'],
].filter(function (l) {
return here === '' || l[1].indexOf('//' + here) === -1;
});
var host = document.createElement('div');
host.id = 'radical-footer-root';
var shadow = host.attachShadow({ mode: 'open' });
var flagLinks = FLAGSHIPS.map(function (l) {
return '<a href="' + l[1] + '">' + l[0] + '</a>';
}).join('');
var barCSS =
':host{all:initial}' +
'*{margin:0;padding:0;box-sizing:border-box;font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace}' +
'.rf{background:#0B0B09;color:#8b8b85;border-top:1px solid rgba(255,255,255,.08);' +
'padding:34px 22px;box-shadow:0 -1px 0 ' + accent + '22}' +
'.rf-in{max-width:1040px;margin:0 auto;display:flex;flex-wrap:wrap;gap:24px 40px;align-items:flex-start;justify-content:space-between}' +
'.rf-brand{display:flex;flex-direction:column;gap:8px;min-width:200px}' +
'.rf-logo{display:inline-flex;align-items:center;gap:9px;text-decoration:none}' +
'.rf-dot{width:11px;height:11px;border-radius:50%;background:' + accent + ';box-shadow:0 0 12px ' + accent + '99;flex:none}' +
'.rf-word{font-family:"Syne","IBM Plex Mono",monospace;font-weight:800;font-size:16px;letter-spacing:.14em;' +
'color:#F0EDE6;text-transform:uppercase}' +
'.rf-vvv{font-size:10px;letter-spacing:.32em;text-transform:uppercase;color:' + accent + '}' +
'.rf-tag{font-size:11px;line-height:1.6;color:#6f6f69;max-width:280px}' +
'.rf-cols{display:flex;gap:52px;flex-wrap:wrap}' +
'.rf-col{display:flex;flex-direction:column;gap:11px}' +
'.rf-h{font-size:9px;letter-spacing:.28em;text-transform:uppercase;color:#55554f;margin-bottom:3px}' +
'.rf a{color:#b7b7b0;text-decoration:none;font-size:12.5px;letter-spacing:.02em;transition:color .15s}' +
'.rf a:hover{color:' + accent + '}' +
'.rf-logo:hover .rf-word{color:' + accent + '}' +
'.rf-btm{max-width:1040px;margin:26px auto 0;padding-top:16px;border-top:1px solid rgba(255,255,255,.06);' +
'display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px;font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:#55554f}' +
'@media(max-width:640px){.rf-cols{gap:32px}.rf{padding:28px 18px}}';
var barHTML =
'<div class="rf"><div class="rf-in">' +
'<div class="rf-brand">' +
'<a class="rf-logo" href="' + HOME + '"><span class="rf-dot"></span><span class="rf-word">Radical</span></a>' +
'<span class="rf-vvv">Vibe · Vote · Veto</span>' +
'<span class="rf-tag">Australias direct-democracy movement — and everything it builds in the open.</span>' +
'</div>' +
'<div class="rf-cols">' +
'<div class="rf-col"><span class="rf-h">Movement</span>' +
'<a href="' + HOME + '">The Platform</a>' +
'<a href="' + HOME + '#about">One Law</a>' +
'<a href="' + HOME + '#join">Join</a>' +
'<a href="' + HUB + '">All Projects</a>' +
'</div>' +
(flagLinks ? '<div class="rf-col"><span class="rf-h">We Build</span>' + flagLinks + '</div>' : '') +
'</div>' +
'</div>' +
'<div class="rf-btm"><span>&copy; 2026 The Radical Party</span><span>Radical by default</span></div>' +
'</div>';
// Slim: one compact line. Renders as a normal block bar (NOT fixed), so it
// sits as a ~40px flex child at the bottom of an app shell without stealing
// the layout the way the full block does, and still flows fine on a scrolling
// page. Accent-matched so it reads as part of the host app, not a foreign box.
var slimCSS =
':host{all:initial}' +
'*{margin:0;padding:0;box-sizing:border-box;font-family:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace}' +
'.rf{background:#0B0B09;color:#8b8b85;border-top:1px solid rgba(255,255,255,.08);' +
'box-shadow:0 -1px 0 ' + accent + '22;padding:9px 18px;display:flex;align-items:center;' +
'gap:8px 22px;flex-wrap:wrap;line-height:1}' +
'.rf-logo{display:inline-flex;align-items:center;gap:8px;text-decoration:none;flex:none}' +
'.rf-dot{width:9px;height:9px;border-radius:50%;background:' + accent + ';box-shadow:0 0 10px ' + accent + '99;flex:none}' +
'.rf-word{font-family:"Syne","IBM Plex Mono",monospace;font-weight:800;font-size:13px;letter-spacing:.14em;' +
'color:#F0EDE6;text-transform:uppercase}' +
'.rf-nav{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;flex:1;min-width:0}' +
'.rf a{color:#b7b7b0;text-decoration:none;font-size:12px;letter-spacing:.02em;transition:color .15s;white-space:nowrap}' +
'.rf a:hover{color:' + accent + '}' +
'.rf-logo:hover .rf-word{color:' + accent + '}' +
'.rf-vvv{font-size:9px;letter-spacing:.28em;text-transform:uppercase;color:' + accent + ';flex:none;white-space:nowrap}' +
'@media(max-width:640px){.rf{padding:9px 14px;gap:8px 14px}.rf-vvv{display:none}}';
var slimHTML =
'<div class="rf">' +
'<a class="rf-logo" href="' + HOME + '"><span class="rf-dot"></span><span class="rf-word">Radical</span></a>' +
'<nav class="rf-nav">' +
flagLinks +
'<a href="' + HUB + '">All Projects ↗</a>' +
'</nav>' +
'<span class="rf-vvv">Vibe · Vote · Veto</span>' +
'</div>';
var pillCSS =
':host{all:initial}' +
'*{margin:0;padding:0;box-sizing:border-box;font-family:"IBM Plex Mono",ui-monospace,monospace}' +
'.rf-pill{position:fixed;right:14px;bottom:14px;z-index:2147483000;display:inline-flex;align-items:center;gap:8px;' +
'background:rgba(11,11,9,.92);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.12);' +
'border-radius:999px;padding:8px 14px;text-decoration:none;box-shadow:0 6px 20px rgba(0,0,0,.4);transition:border-color .15s}' +
'.rf-pill:hover{border-color:' + accent + '}' +
'.rf-dot{width:9px;height:9px;border-radius:50%;background:' + accent + ';box-shadow:0 0 10px ' + accent + '99}' +
'.rf-txt{font-size:11px;letter-spacing:.06em;color:#e7e4dd}.rf-txt b{color:#fff;font-weight:700}' +
'.rf-arrow{color:' + accent + ';font-size:12px}';
var pillHTML =
'<a class="rf-pill" href="' + HUB + '" title="Explore The Radical Party">' +
'<span class="rf-dot"></span>' +
'<span class="rf-txt">Part of <b>The Radical Party</b></span>' +
'<span class="rf-arrow">↗</span></a>';
var css = mode === 'pill' ? pillCSS : mode === 'slim' ? slimCSS : barCSS;
var html = mode === 'pill' ? pillHTML : mode === 'slim' ? slimHTML : barHTML;
shadow.innerHTML = '<style>' + css + '</style>' + html;
function mount() {
if (document.getElementById('radical-footer-root')) return;
document.body.appendChild(host);
}
if (document.body) mount();
else document.addEventListener('DOMContentLoaded', mount);
})();