radical/footer.js
King Omar 7a3b684203 Add shared footer.js — one-line cross-subdomain wayfinding
Self-contained Shadow-DOM component so no subdomain is a dead end.
Loaded via <script src="https://theradicalparty.com/footer.js" defer>.
Two modes: full bar (default) and data-mode="pill" for full-screen apps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 22:36:59 +10:00

120 lines
6.6 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.
- Two modes, chosen via a data attribute on the script tag:
(default) full footer bar at the end of the page.
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' : '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>';
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>';
shadow.innerHTML =
'<style>' + (mode === 'pill' ? pillCSS : barCSS) + '</style>' +
(mode === 'pill' ? pillHTML : barHTML);
function mount() {
if (document.getElementById('radical-footer-root')) return;
document.body.appendChild(host);
}
if (document.body) mount();
else document.addEventListener('DOMContentLoaded', mount);
})();