/** * Hyperclay Newsletter Form * A self-contained, embeddable newsletter signup form * * Usage: * *
* * * Options: * hyperclayNewsletterify(el, { * tags: ['custom-tag'], // Additional tags for the subscriber * onSuccess: (email) => {}, // Called after successful subscription * onError: (error) => {} // Called on error * }); */ (function(global) { 'use strict'; // Embedded SVG icons as data URIs const ICONS = { // Newsletter icon - stylized envelope with checkmark newsletter: `data:image/svg+xml,${encodeURIComponent(``)}`, // Corner decorations - pixelated blocks cornerTopLeft: `data:image/svg+xml,${encodeURIComponent(``)}`, cornerBottomRight: `data:image/svg+xml,${encodeURIComponent(``)}`, // Toast icons toastSuccess: ``, toastError: `` }; // Scoped styles const STYLES = ` .hc-newsletter-form { position: relative; max-width: 400px; margin-left: auto; margin-right: auto; padding-bottom: 16px; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; box-sizing: border-box; } @media (min-width: 640px) { .hc-newsletter-form { max-width: 500px; padding-bottom: 48px; } } .hc-newsletter-form *, .hc-newsletter-form *::before, .hc-newsletter-form *::after { box-sizing: border-box; } .hc-newsletter-header { margin-bottom: 15px; text-align: center; color: #fff; font-size: 16px; } .hc-newsletter-icon { position: relative; top: -4px; display: inline-block; height: 24px; vertical-align: middle; margin-left: 4px; } .hc-input-wrapper { position: relative; height: 40px; margin-bottom: 25px; transition: box-shadow 0.15s ease; } .hc-input-wrapper:focus-within { box-shadow: 0 0 0 4px #0B0C12, 0 0 0 6px #fff; } .hc-honeypot { position: absolute; left: -9999px; opacity: 0; pointer-events: none; } .hc-email-input { position: absolute; inset: 0; width: 100%; height: 100%; padding-top: 9px; text-align: center; color: #1e293b; background: #fff; border: none; outline: none; font-size: 16px; } .hc-email-input::placeholder { color: #94a3b8; } .hc-corner-tl { position: absolute; top: -1px; left: -1px; width: 30px; height: 30px; pointer-events: none; } .hc-corner-br { position: absolute; bottom: -1px; right: -1px; width: 28px; height: 28px; pointer-events: none; } .hc-button-wrapper { text-align: center; } .hc-submit-btn { font-family: 'Fixedsys Excelsior', 'Fixedsys', 'Consolas', 'Courier New', monospace; text-align: center; cursor: pointer; border-width: 3px; border-style: solid; border-top-color: #474C65; border-right-color: #131725; border-bottom-color: #131725; border-left-color: #474C65; background-color: #1D1F2F; padding: 4px 44px 7px; font-size: 23px; color: #fff; transition: background-color 0.1s ease; } @media (min-width: 640px) { .hc-submit-btn { padding: 4px 50px 7px; font-size: 25px; } } .hc-submit-btn:hover { background-color: #232639; } .hc-submit-btn:active { border-top-color: #131725; border-right-color: #474C65; border-bottom-color: #474C65; border-left-color: #131725; } .hc-submit-btn:active .hc-btn-text { transform: translate(1.5px, 1.5px); } .hc-btn-text { display: inline-block; white-space: nowrap; user-select: none; transition: transform 0.05s ease; } /* Toast styles */ .hc-toast-container { z-index: 9999; position: fixed; top: 20px; right: 20px; display: flex; flex-direction: column; align-items: flex-end; } .hc-toast-container > * + * { margin-top: 18px; } .hc-toast { position: relative; right: 0; display: flex; align-items: center; padding: 10px 19px 11px 17px; cursor: pointer; color: rgba(255,255,255,.8); background-color: #0B0C12; border: 2px dashed rgba(255,255,255,.6); transition: right 0.5s ease-in-out, opacity 0.5s ease-in-out; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; } .hc-toast svg { position: relative; top: -1px; width: 17px; height: 17px; margin-right: 13px; flex-shrink: 0; } .hc-toast.hc-hide { right: -300px; opacity: 0; } .hc-toast.hc-success { color: #76C824; border: 2px dashed #589E11; } .hc-toast.hc-error { color: #DD304F; border: 2px dashed #CD2140; } `; // Buttondown API configuration const API_TOKEN = '8b1688f6-5a75-4c45-8da8-09f71d9a5c3b'; const API_URL = 'https://api.buttondown.com/v1/subscribers'; // Inject styles once let stylesInjected = false; function injectStyles() { if (stylesInjected) return; if (document.getElementById('hc-newsletter-styles')) { stylesInjected = true; return; } const styleEl = document.createElement('style'); styleEl.id = 'hc-newsletter-styles'; styleEl.textContent = STYLES; document.head.appendChild(styleEl); stylesInjected = true; } // Toast notification system function showToast(message, type = 'success') { let container = document.querySelector('.hc-toast-container'); if (!container) { container = document.createElement('div'); container.className = 'hc-toast-container'; document.body.appendChild(container); } const icon = type === 'success' ? ICONS.toastSuccess : ICONS.toastError; const toast = document.createElement('div'); toast.className = `hc-toast hc-hide hc-${type}`; toast.innerHTML = `${icon}${message}`; toast.addEventListener('click', () => { toast.classList.add('hc-hide'); setTimeout(() => toast.remove(), 500); }); container.appendChild(toast); setTimeout(() => toast.classList.remove('hc-hide'), 10); setTimeout(() => { toast.classList.add('hc-hide'); setTimeout(() => toast.remove(), 500); }, 6600); } // Generate unique form ID let formCounter = 0; function getUniqueId() { return `hc-newsletter-form-${++formCounter}`; } /** * Insert a fully styled Hyperclay newsletter form into an element * @param {HTMLElement} el - The container element * @param {Object} options - Optional configuration * @param {string[]} options.tags - Additional tags for the subscriber (default: ['embedded-form', 'newsletter']) * @param {Function} options.onSuccess - Called after successful subscription with email * @param {Function} options.onError - Called on error with error object * @returns {HTMLFormElement} The created form element */ function hyperclayNewsletterify(el, options = {}) { if (!el || !(el instanceof HTMLElement)) { console.error('hyperclayNewsletterify: Invalid element provided'); return null; } injectStyles(); const formId = getUniqueId(); const tags = options.tags || ['embedded-form', 'newsletter']; const form = document.createElement('form'); form.id = formId; form.className = 'hc-newsletter-form'; form.innerHTML = `