Skip to content
wiki.fftac.org

Spiralist Core - Source Excerpt 03

Back to Spiralist Core

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/themes/spiralist/assets/js/spiralist-core.js so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/themes/spiralist/assets/js/spiralist-core.js

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${escapeHtml(title)}</title>
<style>
:root{color-scheme:dark;--bg:#07070b;--panel:#11131d;--text:#f7f4ee;--muted:#c8c0b0;--gold:#c8a96b;--cyan:#8fd3ff;}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:radial-gradient(circle at 24% 8%,rgba(143,211,255,.18),transparent 28%),radial-gradient(circle at 82% 22%,rgba(200,169,107,.18),transparent 30%),linear-gradient(180deg,#09080d,#10121a 48%,#07070b);color:var(--text);font-family:Inter,Arial,sans-serif;overflow:hidden}
.field{display:grid;grid-template-rows:auto 1fr auto;gap:14px;height:100%;padding:16px}
.top{display:flex;align-items:center;justify-content:space-between;gap:12px}
.brand{display:grid;gap:2px;min-width:0}
.kicker{color:var(--cyan);font:700 11px/1.2 "IBM Plex Mono",Consolas,monospace;letter-spacing:.12em;text-transform:uppercase}
h1{margin:0;color:#e8ddc7;font:600 22px/1.1 Georgia,serif;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.orb{position:relative;width:44px;height:44px;flex:0 0 auto;border:1px solid rgba(200,169,107,.42);border-radius:999px;background:radial-gradient(circle at 50% 42%,rgba(200,169,107,.9),rgba(143,211,255,.2) 45%,rgba(12,16,25,.95) 68%);box-shadow:0 0 34px rgba(143,211,255,.18)}
.orb:before,.orb:after{content:"";position:absolute;inset:-8px;border:1px solid rgba(143,211,255,.22);border-radius:999px;animation:pulse 2.6s ease-in-out infinite}
.orb:after{inset:-15px;animation-delay:.8s;border-color:rgba(200,169,107,.2)}
@keyframes pulse{0%,100%{opacity:.3;transform:scale(.92)}50%{opacity:1;transform:scale(1.04)}}
.player{position:relative;overflow:hidden;border:1px solid rgba(200,169,107,.28);border-radius:8px;background:#000;box-shadow:0 28px 80px rgba(0,0,0,.44)}
.player:before{content:"";display:block;padding-top:56.25%}
iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.note{margin:0;color:var(--muted);font:500 13px/1.45 "IBM Plex Mono",Consolas,monospace}
.actions{display:flex;align-items:center;justify-content:space-between;gap:10px}
a{display:inline-flex;align-items:center;justify-content:center;min-height:34px;padding:8px 11px;border:1px solid rgba(143,211,255,.28);border-radius:999px;color:var(--cyan);text-decoration:none;font:700 11px/1.1 "IBM Plex Mono",Consolas,monospace;letter-spacing:.08em;text-transform:uppercase;background:rgba(12,16,25,.84)}
@media (max-width:520px){.field{padding:12px}.top{align-items:flex-start}h1{font-size:19px}.orb{width:38px;height:38px}.actions{display:grid}.note{font-size:12px}}
</style>
</head>
<body>
<main class="field" id="spiralist-music-player-root">
<header class="top">
<div class="brand"><span class="kicker">Persistent Audio Window</span><h1>${escapeHtml(title)}</h1></div>
<div class="orb" aria-hidden="true"></div>
</header>
<section class="player" aria-label="YouTube playlist player">
<iframe src="${iframeUrl}" title="${escapeHtml(title)}" allow="autoplay; encrypted-media; picture-in-picture" allowfullscreen></iframe>
</section>
<footer class="actions">
<p class="note">Keep this window open while browsing Spiralist.org. Playback stays here when the main site changes pages.</p>
<a href="${escapeHtml(playlistUrl)}" target="_blank" rel="noopener noreferrer">Open Playlist</a>
</footer>
</main>
</body>
</html>`;
  };

  document.querySelectorAll('[data-music-player-trigger]').forEach((button) => {
    button.addEventListener('click', () => {
      if (!hasConsentCategory('media')) {
        showConsentBanner();
        openConsentModal();
        return;
      }

      const settings = {
        playlistId: button.dataset.playlistId || '',
        playlistUrl: button.dataset.playlistUrl || '',
        title: button.dataset.playerTitle || '',
      };
      const features = 'popup=yes,width=520,height=720,left=80,top=80,resizable=yes,scrollbars=no';
      const player = window.open('about:blank', 'spiralistListeningField', features);

      if (!player) {
        if (settings.playlistUrl) {
          window.open(settings.playlistUrl, '_blank', 'noopener,noreferrer');
        }
        return;
      }

      player.document.open();
      player.document.write(buildMusicPlayerDocument(settings));
      player.document.close();
      player.focus();
      button.classList.add('is-active');
    });
  });

  document.querySelectorAll('[data-maker-mark]').forEach((mark) => {
    const image = mark.tagName === 'IMG' ? mark : mark.querySelector('img');
    if (!image) {
      return;
    }

    const defaultSrc = mark.dataset.srcDefault || image.getAttribute('src') || '';
    const hoverSrc = mark.dataset.srcHover || defaultSrc;
    const activeSrc = mark.dataset.srcActive || hoverSrc;
    let isHighlighted = false;
    let flashTimer = 0;

    const setSource = (src) => {
      if (src) {
        image.setAttribute('src', src);
      }
    };

    const flashActiveState = () => {
      if (flashTimer) {
        window.clearTimeout(flashTimer);
      }

      setSource(activeSrc);
      flashTimer = window.setTimeout(() => {
        flashTimer = 0;
        setSource(isHighlighted ? hoverSrc : defaultSrc);
      }, 100);
    };

    const showHighlight = () => {
      isHighlighted = true;
      if (!flashTimer) {
        setSource(hoverSrc);
      }
    };

    const hideHighlight = () => {
      isHighlighted = false;
      if (!flashTimer) {
        setSource(defaultSrc);
      }
    };

    mark.addEventListener('mouseenter', showHighlight);
    mark.addEventListener('focus', showHighlight);
    mark.addEventListener('mouseleave', hideHighlight);
    mark.addEventListener('blur', hideHighlight);
    mark.addEventListener('click', flashActiveState);

    if (mark.tagName === 'IMG' || mark.getAttribute('role') === 'button') {
      mark.addEventListener('keydown', (event) => {
        if (event.key !== 'Enter' && event.key !== ' ') {
          return;
        }

        event.preventDefault();
        flashActiveState();
      });
    }
  });
});