Add El source files for all client-side JS

Recovers original JS from git history and ports it into proper El source
files under src/js/. Each file wraps the original JS in a native_js call
inside a main() function, making it valid El that compiles to a
self-contained IIFE via elc --target=js --bundle.

Files added:
  src/js/account-auth.el       - Supabase OTP magic-link (sendMagicLink)
  src/js/account-dashboard.el  - Account dashboard: session, plan card, family
  src/js/chat-widget.el        - Demo chat widget (neuronDemoToggle/Send/Reset)
  src/js/checkout-auth.el      - Checkout auth: OAuth, email sign-in/up
  src/js/checkout-free.el      - Free plan: auth-badge watch -> payment reveal
  src/js/checkout-stripe.el    - Stripe Payment Element (reads NEURON_CFG)
  src/js/enterprise.el         - Enterprise inquiry form + headcount filter
  src/js/environmental.el      - Efficiency calculator slider
  src/js/gallery.el            - Gallery nav, search/sort, Supabase voting
  src/js/main.el               - Share page voting + copyForPlatform
  src/js/marketplace.el        - Developer interest form
  src/js/nav.el                - Nav hamburger + Mission dropdown
  src/js/styles.el             - Landing: nav scroll, reveal, founding counter
This commit is contained in:
Will Anderson
2026-05-04 11:23:21 -05:00
parent 246a5f0967
commit 94f6e749a0
44 changed files with 1625 additions and 642 deletions
+40
View File
@@ -0,0 +1,40 @@
// account-auth.el -- Supabase OTP magic-link auth for the account page.
// Sends a PKCE magic link to the user's email address.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Required HTML elements: #acct-email-input, #acct-magic-btn, #acct-email-msg
// Required globals: window.NEURON_CFG.supabase_url, window.NEURON_CFG.supabase_anon_key
// Required CDN: supabase-js@2 loaded before this script
fn main() -> Void {
native_js("(function() {
'use strict';
var cfg = window.NEURON_CFG || {};
var sb = supabase.createClient(cfg.supabase_url, cfg.supabase_anon_key, {
auth: { flowType: 'pkce' }
});
window.sendMagicLink = async function() {
var email = (document.getElementById('acct-email-input').value || '').trim();
var msgEl = document.getElementById('acct-email-msg');
var btn = document.getElementById('acct-magic-btn');
if (!email) {
msgEl.style.display = 'block';
msgEl.style.color = '#c44';
msgEl.textContent = 'Please enter your email address.';
return;
}
if (btn) { btn.disabled = true; btn.textContent = 'Sending...'; }
var result = await sb.auth.signInWithOtp({ email: email });
if (btn) { btn.disabled = false; btn.textContent = 'Continue with email'; }
msgEl.style.display = 'block';
if (result.error) {
msgEl.style.color = '#c44';
msgEl.textContent = result.error.message;
} else {
msgEl.style.color = 'var(--navy)';
msgEl.textContent = 'Check your inbox — we sent a sign-in link to ' + email + '.';
}
};
})()")
}
+277
View File
@@ -0,0 +1,277 @@
// account-dashboard.el -- Account dashboard: session check, plan card, family.
// Handles onAuthStateChange, plan card rendering, family member management.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Required globals: window.NEURON_CFG.supabase_url, window.NEURON_CFG.supabase_anon_key
// Required CDN: supabase-js@2
fn main() -> Void {
native_js("(function() {
'use strict';
var cfg = window.NEURON_CFG || {};
var sb = supabase.createClient(cfg.supabase_url, cfg.supabase_anon_key, {
auth: { flowType: 'implicit' }
});
function show(id) { var el = document.getElementById(id); if (el) el.style.display = ''; }
function hide(id) { var el = document.getElementById(id); if (el) el.style.display = 'none'; }
function setText(id, text) { var el = document.getElementById(id); if (el) el.textContent = text; }
function setHtml(id, html) { var el = document.getElementById(id); if (el) el.innerHTML = html; }
window.signInWith = async function(provider) {
var btn = document.getElementById('btn-' + provider);
if (btn) { btn.disabled = true; btn.style.opacity = '0.6'; }
try {
var result = await sb.auth.signInWithOAuth({
provider: provider,
options: { redirectTo: window.location.origin + '/account' }
});
if (result.error) {
if (btn) { btn.disabled = false; btn.style.opacity = '1'; }
}
} catch (e) {
if (btn) { btn.disabled = false; btn.style.opacity = '1'; }
}
};
window.signInWithEmail = async function() {
var email = document.getElementById('acct-email-input').value.trim();
var pass = document.getElementById('acct-pass-input').value;
var msg = document.getElementById('acct-email-msg');
var signinBtn = document.getElementById('acct-signin-btn');
if (!sb) { msg.style.display='block'; msg.style.color='#c44'; msg.textContent='Loading... try again in a moment.'; return; }
if (!email || !pass) {
msg.style.display='block'; msg.style.color='#c44'; msg.textContent='Please enter your email and password.'; return;
}
if (signinBtn) { signinBtn.disabled=true; signinBtn.textContent='Signing in...'; }
var result = await sb.auth.signInWithPassword({ email: email, password: pass });
if (result.error) {
if (result.error.message && result.error.message.toLowerCase().includes('invalid')) {
var signupResult = await sb.auth.signUp({
email: email, password: pass,
options: { emailRedirectTo: window.location.origin + '/account' }
});
if (signupResult.error) {
msg.style.display='block'; msg.style.color='#c44'; msg.textContent=signupResult.error.message; return;
}
msg.style.display='block'; msg.style.color='var(--navy)'; msg.textContent='Check your email to confirm your account.'; return;
}
if (signinBtn) { signinBtn.disabled=false; signinBtn.textContent='Sign in'; }
msg.style.display='block'; msg.style.color='#c44'; msg.textContent=result.error.message; return;
}
window.location.reload();
};
window.signOut = async function() {
var btn = document.getElementById('signout-btn');
var btnTop = document.getElementById('signout-btn-top');
if (btn) { btn.disabled=true; btn.textContent='Signing out...'; }
if (btnTop) { btnTop.disabled=true; btnTop.textContent='Signing out...'; }
await sb.auth.signOut();
show('signin-section');
hide('dashboard-section');
if (btn) { btn.disabled=false; btn.textContent='Sign out'; }
if (btnTop) { btnTop.disabled=false; btnTop.textContent='Sign out'; }
};
async function renderPlanCard(row) {
var plan = (row && row.plan) ? row.plan : 'free';
var memberNum = (row && row.member_number) ? row.member_number : null;
var createdAt = (row && row.created_at) ? row.created_at : null;
var planNames = { 'founding': 'Founding Member', 'professional': 'Professional', 'free': 'Free' };
setText('plan-name-el', planNames[plan] || 'Free');
var statusHtml = '';
if (plan === 'founding' || plan === 'professional') {
statusHtml = '<span class=\"status-badge-preorder\" style=\"margin-top:.625rem;display:inline-flex\">'
+ '<svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/></svg>'
+ 'Launching within 30 days</span>';
} else {
statusHtml = '<span class=\"plan-status\" style=\"margin-top:.625rem;display:inline-flex\"><span class=\"plan-status-dot\"></span>Active</span>';
}
setHtml('plan-status-el', statusHtml);
var billingNote = '';
if (plan === 'founding') {
billingNote = '<p class=\"plan-billing-note\">Lifetime &middot; Never billed again</p>';
} else if (plan === 'professional') {
billingNote = '<p class=\"plan-billing-note\">Billed monthly &middot; <button class=\"plan-billing-link\" onclick=\"window.location.href=\'/contact\'\">Cancel</button></p>';
} else {
billingNote = '<p class=\"plan-billing-note\">On the waitlist</p>';
}
setHtml('plan-billing-note-el', billingNote);
var meta = '';
if (createdAt) {
var d = new Date(createdAt);
var dateStr = d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
meta += '<div class=\"plan-meta-item\"><span class=\"plan-meta-label\">Joined</span><span class=\"plan-meta-value\">' + dateStr + '</span></div>';
}
if (memberNum) {
meta += '<div class=\"plan-meta-item\"><span class=\"plan-meta-label\">Member number</span><span class=\"plan-meta-value\">#' + memberNum + ' of 1,000</span></div>';
}
if (meta) setHtml('plan-meta-el', meta);
if (plan === 'founding') {
var badgeSection = document.getElementById('badge-section');
var badgeContainer = document.getElementById('badge-html-container');
if (badgeSection) badgeSection.style.display = '';
var badgeN = memberNum || 0;
fetch('/api/founding-badge?n=' + badgeN)
.then(function(r) { return r.text(); })
.then(function(html) { if (badgeContainer) badgeContainer.innerHTML = html; })
.catch(function() {});
}
var roadmapSection = document.getElementById('roadmap-section');
if (plan === 'founding' && roadmapSection) roadmapSection.style.display = '';
if (plan === 'founding') {
var famSection = document.getElementById('family-section');
if (famSection) famSection.style.display = 'block';
var session = await sb.auth.getSession();
var userEmail = session.data.session && session.data.session.user ? session.data.session.user.email : '';
if (userEmail) loadFamilyMembers(userEmail);
}
}
async function loadFamilyMembers(parentEmail) {
var r = await fetch('/api/family/members?parent_email=' + encodeURIComponent(parentEmail));
var members = await r.json();
var list = document.getElementById('family-list');
if (!list) return;
if (!members || !members.length) {
list.innerHTML = '<p style=\"color:var(--t3);font-size:.875rem;margin-bottom:1rem\">No family members yet.</p>';
return;
}
list.innerHTML = members.map(function(m) {
return '<div style=\"display:flex;justify-content:space-between;align-items:center;padding:.75rem 0;border-bottom:1px solid var(--border)\">'
+ '<div><p style=\"font-size:.875rem;color:var(--t1)\">' + m.child_email + '</p>'
+ '<p style=\"font-size:.75rem;color:var(--t3);text-transform:uppercase;letter-spacing:.06em\">' + m.status + '</p></div>'
+ '<button onclick=\"removeFamilyMember(\'' + m.child_email + '\')\" style=\"background:none;border:none;color:var(--t3);cursor:pointer;font-size:.75rem\">Remove</button>'
+ '</div>';
}).join('');
}
window.addFamilyMember = async function() {
var email = document.getElementById('child-email').value.trim();
var year = document.getElementById('child-dob-year').value;
var attest = document.getElementById('family-attest').checked;
var msg = document.getElementById('family-msg');
if (!email || !year || !attest) {
msg.style.display='block'; msg.style.color='#c44'; msg.textContent='Please fill in all fields and confirm the attestation.'; return;
}
if (parseInt(year) < 2008) {
msg.style.display='block'; msg.style.color='#c44'; msg.textContent='Child must be under 18. Birth year must be 2008 or later.'; return;
}
var session = await sb.auth.getSession();
var parentEmail = session.data.session && session.data.session.user ? session.data.session.user.email : '';
var r = await fetch('/api/family/invite', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({parent_email: parentEmail, child_email: email, child_dob_year: parseInt(year), attested: true})
});
var d = await r.json();
msg.style.display = 'block';
if (d.ok) {
msg.style.color = 'var(--navy)';
msg.textContent = 'Invitation sent to ' + email + '. They will receive an email to set up their account.';
document.getElementById('child-email').value = '';
document.getElementById('child-dob-year').value = '';
document.getElementById('family-attest').checked = false;
loadFamilyMembers(parentEmail);
} else {
msg.style.color = '#c44';
msg.textContent = d.error || 'Something went wrong.';
}
};
window.removeFamilyMember = async function(childEmail) {
var session = await sb.auth.getSession();
var parentEmail = session.data.session && session.data.session.user ? session.data.session.user.email : '';
await fetch('/api/family/remove', {
method: 'POST', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({parent_email: parentEmail, child_email: childEmail})
});
loadFamilyMembers(parentEmail);
};
function renderUserChip(user) {
var email = user.email || '';
var avatarEl = document.getElementById('user-avatar-el');
var emailEl = document.getElementById('user-email-el');
var headerEmailEl = document.getElementById('acct-header-email');
if (emailEl) emailEl.textContent = email;
if (headerEmailEl) headerEmailEl.textContent = email;
var avatarUrl = user.user_metadata && user.user_metadata.avatar_url;
if (avatarEl) {
if (avatarUrl) {
avatarEl.innerHTML = '<img src=\"' + avatarUrl + '\" alt=\"\" referrerpolicy=\"no-referrer\">';
} else {
avatarEl.textContent = email ? email.charAt(0).toUpperCase() : '?';
}
}
}
function showNoPlan() {
var el = document.getElementById('plan-card');
if (!el) return;
el.innerHTML = '<div class=\"card-label\">Your plan</div>'
+ '<p style=\"font-family:var(--body);font-weight:500;font-size:1.125rem;color:var(--t1);margin-bottom:.75rem\">No active plan</p>'
+ '<p style=\"font-family:var(--body);font-weight:300;font-size:.9rem;color:var(--t2);line-height:1.7;margin-bottom:1.5rem\">You have an account but no plan selected yet. Pick one below to preorder.</p>'
+ '<div style=\"display:flex;gap:1rem;flex-wrap:wrap\">'
+ '<a href=\"/checkout?plan=founding\" class=\"btn-primary\" style=\"padding:.75rem 1.5rem\">Founding Member - $199 &rarr;</a>'
+ '<a href=\"/checkout?plan=professional\" class=\"btn-ghost\" style=\"padding:.75rem 1.5rem\">Professional - $19/mo</a>'
+ '<a href=\"/checkout?plan=free\" class=\"btn-ghost\" style=\"padding:.75rem 1.5rem\">Free tier</a>'
+ '</div>';
}
async function loadWaitlistData() {
try {
var sess = await sb.auth.getSession();
var token = sess.data && sess.data.session ? sess.data.session.access_token : '';
if (!token) { showNoPlan(); return; }
var r = await fetch('/api/my-plan', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({access_token: token})
});
var row = await r.json();
if (!row || !row.plan) { showNoPlan(); return; }
renderPlanCard(row);
} catch (e) {
showNoPlan();
}
}
function showDashboard(user) {
hide('signin-section');
show('dashboard-section');
renderUserChip(user);
loadWaitlistData();
}
async function init() {
var result = await sb.auth.getSession();
var session = result.data && result.data.session;
if (session && session.user) {
showDashboard(session.user);
} else {
show('signin-section');
hide('dashboard-section');
}
sb.auth.onAuthStateChange(function(event, session) {
if (session && session.user) {
showDashboard(session.user);
} else {
show('signin-section');
hide('dashboard-section');
}
});
}
init();
})()")
}
+305
View File
@@ -0,0 +1,305 @@
// chat-widget.el -- Neuron demo chat widget with Turnstile, session persistence,
// local engram graph, and share-pill.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Exposed globals: neuronDemoToggle(), neuronDemoSend(), neuronDemoReset()
// Required CDN: marked.js, Cloudflare Turnstile
fn main() -> Void {
native_js("(function() {
if (typeof marked !== 'undefined') { marked.setOptions({ breaks: true, gfm: true }); }
var TURNSTILE_SITE_KEY = '0x4AAAAAADHAZXyuRb3yD9mr';
var turnstileToken = '';
var turnstileWidgetId = null;
var turnstileVerified = false;
var isOpen = false;
var MAX = 10;
function loadSession() {
try {
var s = localStorage.getItem('neuron_demo_session');
return s ? JSON.parse(s) : { messages: [], count: 0, context: '' };
} catch(e) { return { messages: [], count: 0, context: '' }; }
}
function saveSession(session) {
try { localStorage.setItem('neuron_demo_session', JSON.stringify(session)); } catch(e) {}
}
function clearSession() {
try { localStorage.removeItem('neuron_demo_session'); } catch(e) {}
}
function _mg(s) { return s._m || { nodes: [], edges: [] }; }
function _um(s, nn, ne) {
if (!nn || !nn.length) return;
var g = _mg(s), nm = {}, ek = function(e) { return e.from + '->' + e.to; }, em = {};
g.nodes.forEach(function(n) { nm[n.id] = n; });
(nn || []).forEach(function(n) {
if (nm[n.id]) { nm[n.id].w = Math.min(1.0, (nm[n.id].w || 0.5) + 0.08); }
else { nm[n.id] = n; }
});
g.nodes = Object.values(nm);
g.edges.forEach(function(e) { em[ek(e)] = e; });
(ne || []).forEach(function(e) {
var k = ek(e);
if (em[k]) { em[k].weight = Math.min(1.0, (em[k].weight || 0.5) + 0.05); }
else { em[k] = e; }
});
g.edges = Object.values(em);
s._m = g; saveSession(s);
}
function _ra(g, q) {
if (!g || !g.nodes || !g.nodes.length) return [];
var words = q.toLowerCase().split(/\s+/).filter(function(w) { return w.length > 3; });
var sc = {};
g.nodes.forEach(function(n) {
var t = (n.content || '').toLowerCase();
sc[n.id] = words.filter(function(w) { return t.indexOf(w) !== -1; }).length * 0.6 + (n.w || 0.5) * 0.4;
});
(g.edges || []).forEach(function(e) {
if (sc[e.from] > 0.1) sc[e.to] = (sc[e.to] || 0) + sc[e.from] * (e.weight || 0.5) * 0.4;
});
return g.nodes.filter(function(n) { return sc[n.id] > 0.2; })
.sort(function(a, b) { return sc[b.id] - sc[a.id]; }).slice(0, 5)
.map(function(n) { return { id: n.id, content: n.content, score: sc[n.id] }; });
}
if (window.location.search.indexOf('reset=1') !== -1) {
clearSession();
window.history.replaceState({}, '', window.location.pathname);
}
var session = loadSession();
if (!session.uid) {
session.uid = 'u' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
saveSession(session);
}
var msgCount = session.count || 0;
function updateCountdown() {
var el = document.getElementById('neuron-demo-countdown');
if (!el) return;
var remaining = MAX - msgCount;
el.textContent = remaining + ' question' + (remaining === 1 ? '' : 's') + ' left';
el.style.color = '#ffffff';
el.style.fontWeight = '700';
}
window.neuronDemoReset = function() {
clearSession();
session = { messages: [], count: 0, context: '' };
msgCount = 0;
var msgs = document.getElementById('neuron-demo-messages');
if (msgs) msgs.innerHTML = '';
var input = document.getElementById('neuron-demo-text');
if (input) { input.disabled = false; input.placeholder = 'Ask me anything...'; }
var btn = document.getElementById('neuron-demo-send');
if (btn) btn.disabled = false;
addMsg('ai', 'Hey. What is on your mind?', true);
};
window.neuronDemoToggle = function() {
isOpen = !isOpen;
var panel = document.getElementById('neuron-demo-panel');
if (panel) panel.style.display = isOpen ? 'flex' : 'none';
var btn = document.getElementById('neuron-demo-btn');
if (btn) btn.style.display = isOpen ? 'none' : '';
var msgs = document.getElementById('neuron-demo-messages');
if (isOpen && turnstileVerified && msgs && msgs.style.display !== 'none' && msgs.children.length === 0) {
if (session.messages && session.messages.length > 0) {
session.messages.forEach(function(m) { addMsg(m.role, m.text, true); });
var remaining = MAX - msgCount;
if (remaining <= 0) {
var input = document.getElementById('neuron-demo-text');
if (input) { input.disabled = true; input.placeholder = 'Interaction limit reached'; }
}
} else if (!session.greeted) {
addMsg('ai', 'Hey. What is on your mind?', true);
session.greeted = true;
saveSession(session);
}
}
var input = document.getElementById('neuron-demo-text');
if (isOpen && input && !input.disabled) input.focus();
updateCountdown();
if (isOpen && !turnstileWidgetId && typeof turnstile !== 'undefined') {
var container = document.getElementById('neuron-demo-turnstile');
if (container) {
turnstileWidgetId = turnstile.render(container, {
sitekey: TURNSTILE_SITE_KEY,
size: 'compact',
callback: function(token) {
turnstileToken = token;
turnstileVerified = true;
if (typeof turnstile !== 'undefined' && turnstileWidgetId !== null) {
try { turnstile.remove(turnstileWidgetId); } catch(e) {}
turnstileWidgetId = null;
}
var gate = document.getElementById('neuron-demo-gate');
var msgs = document.getElementById('neuron-demo-messages');
var inputRow = document.getElementById('neuron-demo-input-row');
if (gate) gate.style.display = 'none';
if (msgs) msgs.style.display = 'flex';
if (inputRow) inputRow.style.display = 'flex';
addMsg('ai', 'Hey. What is on your mind?', true);
updateCountdown();
var inp = document.getElementById('neuron-demo-text');
if (inp) inp.focus();
},
'expired-callback': function() {
turnstileToken = '';
turnstileVerified = false;
}
});
}
}
};
function addMsg(role, text, skipSave) {
var msgs = document.getElementById('neuron-demo-messages');
if (!msgs) return null;
var el = document.createElement('div');
el.className = 'demo-msg demo-msg-' + role;
var avatar = document.createElement('div');
avatar.className = 'demo-msg-avatar';
if (role === 'ai') {
var img = document.createElement('img');
img.src = '/assets/brand/neuron-brain.png'; img.alt = 'Neuron';
avatar.appendChild(img);
} else {
var svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg');
svg.setAttribute('width', '14'); svg.setAttribute('height', '14');
svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('fill', 'none');
svg.setAttribute('stroke', 'currentColor'); svg.setAttribute('stroke-width', '2');
var p1 = document.createElementNS(svgNS, 'path');
p1.setAttribute('d', 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2');
var c1 = document.createElementNS(svgNS, 'circle');
c1.setAttribute('cx', '12'); c1.setAttribute('cy', '7'); c1.setAttribute('r', '4');
svg.appendChild(p1); svg.appendChild(c1); avatar.appendChild(svg);
}
var bubble = document.createElement('div');
bubble.className = 'demo-msg-bubble';
if (role === 'ai' && typeof marked !== 'undefined') {
try { bubble.innerHTML = marked.parse(text); } catch(e) { bubble.textContent = text; }
} else {
bubble.textContent = text;
}
if (role === 'ai') {
var bodyWrap = document.createElement('div');
bodyWrap.className = 'demo-msg-ai-body';
bodyWrap.appendChild(bubble);
if (!skipSave) {
var shareBtn = document.createElement('button');
shareBtn.className = 'demo-share-pill'; shareBtn.title = 'Share this response'; shareBtn.textContent = 'Share ↗';
shareBtn.onclick = async function() {
var prevUser = '';
if (session.messages) {
for (var i = session.messages.length - 1; i >= 0; i--) {
if (session.messages[i].role === 'user') { prevUser = session.messages[i].text; break; }
}
}
shareBtn.style.opacity = '0.4';
try {
var r = await fetch('/api/share', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ question: prevUser, answer: text })
});
var d = await r.json();
if (d.id) window.open('/share/' + d.id, '_blank');
} catch(e) {}
shareBtn.style.opacity = '1';
};
bodyWrap.appendChild(shareBtn);
}
el.appendChild(avatar); el.appendChild(bodyWrap);
} else {
el.appendChild(avatar); el.appendChild(bubble);
}
msgs.appendChild(el);
msgs.scrollTop = msgs.scrollHeight;
if (!skipSave && role !== 'thinking') {
session.messages = session.messages || [];
session.messages.push({ role: role, text: text });
if (session.messages.length > 40) session.messages = session.messages.slice(-40);
saveSession(session);
}
return el;
}
window.neuronDemoSend = async function() {
if (msgCount >= MAX) return;
var input = document.getElementById('neuron-demo-text');
var btn = document.getElementById('neuron-demo-send');
if (!input || btn.disabled) return;
var msg = input.value.trim();
if (!msg) return;
input.value = '';
btn.disabled = true;
addMsg('user', msg);
var thinking = document.createElement('div');
thinking.className = 'demo-msg demo-msg-thinking';
var thAvatar = document.createElement('div');
thAvatar.className = 'demo-msg-avatar';
var thImg = document.createElement('img');
thImg.src = '/assets/brand/neuron-brain.png'; thImg.alt = 'Neuron';
thAvatar.appendChild(thImg); thinking.appendChild(thAvatar);
var thDots = document.createElement('span');
thDots.className = 'demo-msg-thinking-dots';
thDots.innerHTML = '<span></span><span></span><span></span>';
thinking.appendChild(thDots);
var thMsgsEl = document.getElementById('neuron-demo-messages');
if (thMsgsEl) { thMsgsEl.appendChild(thinking); thMsgsEl.scrollTop = thMsgsEl.scrollHeight; }
try {
var hist = (session.messages || []).slice(-20).filter(function(m) { return m.role !== 'thinking'; }).map(function(m) {
return { role: m.role === 'ai' ? 'assistant' : 'user', content: m.text };
});
var activated_nodes = _ra(session._m, msg);
var questionsRemaining = Math.max(0, (MAX - msgCount) - 1);
var r = await fetch('/api/demo', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
message: msg,
history: hist,
cf_token: turnstileVerified && !session._cfSent ? turnstileToken : '',
uid: session.uid || '',
activated_nodes: activated_nodes,
engram_node_count: (session._m && session._m.nodes) ? session._m.nodes.length : 0,
questions_remaining: questionsRemaining,
is_last_question: questionsRemaining === 0
})
});
var d = await r.json();
if (thinking) thinking.remove();
_um(session, d.sn, d.se);
var reply = d.response || d.reply || d.message || '';
var isError = !reply || reply === 'Stepped out for a moment. Try again.';
if (!isError) {
msgCount++;
session.count = msgCount;
saveSession(session);
updateCountdown();
if (msgCount >= MAX && input) { input.disabled = true; input.placeholder = 'Interaction limit reached'; }
}
addMsg('ai', reply || 'Stepped out for a moment. Try again.');
} catch(e) {
if (thinking) thinking.remove();
addMsg('ai', 'Stepped out for a moment. Try again.');
}
if (msgCount < MAX && btn) btn.disabled = false;
if (input) input.focus();
};
var inp = document.getElementById('neuron-demo-text');
if (inp) {
inp.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); window.neuronDemoSend(); }
});
}
})()")
}
+156
View File
@@ -0,0 +1,156 @@
// checkout-auth.el -- Checkout Supabase auth: OAuth, email sign-in/sign-up.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Exposed globals: signInWith(provider), signUpWithEmail(), signInWithEmail(),
// showSignIn(), showSignUp(), resetPassword()
fn main() -> Void {
native_js("(function() {
var supabaseClient;
function initSupabase(cb) {
if (supabaseClient) { cb(); return; }
fetch('/api/supabase-config')
.then(function(r) { return r.json(); })
.then(function(cfg) {
supabaseClient = window.supabase.createClient(cfg.url, cfg.anon_key, {
auth: { flowType: 'implicit' }
});
cb();
})
.catch(function(err) {});
}
function showAuthMessage(msg, isError) {
var el = document.getElementById('auth-message');
if (!el) return;
el.textContent = msg;
el.style.display = 'block';
el.style.color = isError ? '#c0392b' : '#2ecc71';
}
function revealPaymentForm(user) {
if (user && user.id) { window._neuronSupaId = user.id; }
var auth = document.getElementById('auth-section');
if (auth) auth.style.display = 'none';
var payment = document.getElementById('payment-section');
if (payment) payment.style.display = '';
if (user) {
var badge = document.getElementById('auth-badge');
var name = user.user_metadata && user.user_metadata.full_name
? user.user_metadata.full_name : user.email || '';
if (badge) {
badge.innerHTML = '<div class=\"checkout-auth-badge\">'
+ '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M20 6L9 17l-5-5\" stroke=\"#0052A0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'
+ 'Signed in as <strong>' + name + '</strong></div>';
badge.style.display = '';
}
var prompt = document.getElementById('signin-prompt');
if (prompt) prompt.style.display = 'none';
}
if (user && user.email) {
var emailEl = document.getElementById('buyer-email');
if (emailEl) emailEl.value = user.email;
}
var userEmail = user ? (user.email || '') : '';
var userName = user ? ((user.user_metadata && user.user_metadata.full_name) || '') : '';
if (typeof initStripe === 'function') initStripe(userEmail, userName);
}
function checkExistingSession() {
initSupabase(function() {
supabaseClient.auth.getUser().then(function(res) {
if (res.data && res.data.user) { revealPaymentForm(res.data.user); }
});
});
}
function handleAuthRedirect() {
initSupabase(function() {
supabaseClient.auth.onAuthStateChange(function(event, session) {
if ((event === 'SIGNED_IN' || event === 'INITIAL_SESSION') && session && session.user) {
revealPaymentForm(session.user);
}
});
});
}
window.signInWith = function(provider) {
var btns = document.querySelectorAll('.checkout-social-btn');
btns.forEach(function(b) { b.disabled = true; });
initSupabase(function() {
supabaseClient.auth.signInWithOAuth({
provider: provider,
options: { redirectTo: window.location.href }
}).then(function(result) {
if (result.error) {
showAuthMessage(result.error.message || 'Sign-in failed. Please try again.', true);
btns.forEach(function(b) { b.disabled = false; });
}
});
});
};
window.signUpWithEmail = function() {
var email = document.getElementById('auth-email').value.trim();
var password = document.getElementById('auth-password').value;
if (!email || !password) { showAuthMessage('Please enter your email and a password.', true); return; }
if (password.length < 8) { showAuthMessage('Password must be at least 8 characters.', true); return; }
initSupabase(function() {
supabaseClient.auth.signUp({ email: email, password: password }).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); return; }
if (result.data && result.data.session) {
revealPaymentForm(result.data.session.user);
} else {
showAuthMessage('Check your email to confirm your account, then come back to complete your purchase.', false);
}
});
});
};
window.showSignIn = function() {
var form = document.getElementById('email-auth-form');
if (!form) return;
var btn = form.querySelector('.checkout-email-btn');
if (btn) { btn.textContent = 'Sign in →'; btn.onclick = window.signInWithEmail; }
};
window.showSignUp = function() {
var form = document.getElementById('email-auth-form');
if (!form) return;
var btn = form.querySelector('.checkout-email-btn');
if (btn) { btn.textContent = 'Create account →'; btn.onclick = window.signUpWithEmail; }
};
window.signInWithEmail = function() {
var email = document.getElementById('auth-email').value.trim();
var password = document.getElementById('auth-password').value;
if (!email || !password) { showAuthMessage('Please enter your email and password.', true); return; }
initSupabase(function() {
supabaseClient.auth.signInWithPassword({ email: email, password: password }).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); return; }
revealPaymentForm(result.data.session.user);
});
});
};
window.resetPassword = function() {
var email = document.getElementById('auth-email').value.trim();
if (!email) { showAuthMessage('Enter your email address above first.', true); return; }
initSupabase(function() {
supabaseClient.auth.resetPasswordForEmail(email, {
redirectTo: window.location.origin + '/checkout?plan=' + (new URLSearchParams(window.location.search).get('plan') || 'professional')
}).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); }
else { showAuthMessage('Password reset email sent. Check your inbox.', false); }
});
});
};
handleAuthRedirect();
checkExistingSession();
})()")
}
+17
View File
@@ -0,0 +1,17 @@
// checkout-free.el -- Free plan: reveal payment section after auth completes.
// Watches the auth-badge element; when it becomes visible, shows payment-section.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
var pay = document.getElementById('payment-section');
if (!pay) return;
var timer = setInterval(function() {
var badge = document.getElementById('auth-badge');
if (badge && badge.offsetParent !== null) {
pay.style.display = '';
clearInterval(timer);
}
}, 150);
})()")
}
+200
View File
@@ -0,0 +1,200 @@
// checkout-stripe.el -- Stripe Payment Element setup and form submission.
// Reads NEURON_CFG.plan and NEURON_CFG.pub_key from window.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Required globals: window.NEURON_CFG.plan, window.NEURON_CFG.pub_key
// Required CDN: Stripe.js loaded before this script
fn main() -> Void {
native_js("(function() {
var cfg = window.NEURON_CFG || {};
var PLAN = cfg.plan || '';
var STRIPE_PK = cfg.pub_key || '';
var stripe, elements;
function waitForStripe(cb) {
if (window.Stripe) { cb(); return; }
setTimeout(function() { waitForStripe(cb); }, 50);
}
function showMessage(msg) {
var el = document.getElementById('payment-message');
if (el) { el.textContent = msg; el.style.display = 'block'; }
}
function setLoading(loading) {
var btn = document.getElementById('submit-btn');
var label = document.getElementById('submit-label');
var spinner = document.getElementById('submit-spinner');
if (btn) btn.disabled = loading;
if (label) label.style.display = loading ? 'none' : '';
if (spinner) spinner.style.display = loading ? '' : 'none';
}
window._neuronMode = 'payment';
var paymentEl = null;
function appearance() {
return {
theme: 'flat',
variables: {
colorPrimary: '#0052A0',
colorBackground: '#ffffff',
colorText: '#1A1A2E',
colorDanger: '#c0392b',
colorTextPlaceholder: '#9B9BAD',
borderRadius: '0px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontSizeBase: '15px',
fontWeightNormal: '300',
spacingUnit: '4px'
},
rules: {
'.Input': { border: '1px solid rgba(0,82,160,.22)', boxShadow: 'none', padding: '10px 14px' },
'.Input:focus': { border: '1px solid rgba(0,82,160,.6)', boxShadow: '0 0 0 3px rgba(0,82,160,.08)', outline: 'none' },
'.Label': { fontSize: '11px', fontWeight: '500', letterSpacing: '.06em', textTransform: 'uppercase', color: '#6B6B7E', marginBottom: '6px' },
'.Tab': { border: '1px solid rgba(0,82,160,.18)', boxShadow: 'none' },
'.Tab--selected':{ border: '1px solid rgba(0,82,160,.5)', boxShadow: '0 0 0 2px rgba(0,82,160,.12)' },
'.Error': { color: '#c0392b' }
}
};
}
function currentTiming() {
var later = document.getElementById('timing-later');
return (later && later.checked) ? 'later' : 'now';
}
function fetchAndMount() {
var submitBtn = document.getElementById('submit-btn');
if (submitBtn) submitBtn.disabled = true;
if (paymentEl) { try { paymentEl.unmount(); } catch(e) {} paymentEl = null; }
var hostEl = document.getElementById('payment-element');
if (hostEl && !document.querySelector('.checkout-element-loading')) {
var d = document.createElement('div');
d.className = 'checkout-element-loading';
d.textContent = 'Loading payment form...';
hostEl.appendChild(d);
}
var timing = currentTiming();
return fetch('/api/payment-intent', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ plan: PLAN, timing: timing })
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.error === 'sold_out') {
showMessage('All 1,000 Founding Member spots have been claimed. Thank you for your interest - please consider the Professional plan.');
if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'Sold out'; }
return;
}
if (!data.client_secret) { showMessage('Unable to initialise payment. Please try again.'); return; }
window._neuronMode = data.setup_mode ? 'setup' : 'payment';
window._neuronPiId = data.id || (data.client_secret ? data.client_secret.split('_secret_')[0] : '');
var submitLabel = document.getElementById('submit-label');
if (submitLabel) {
submitLabel.textContent = window._neuronMode === 'setup'
? 'Save my card - no charge today →'
: 'Complete purchase →';
}
waitForStripe(function() {
if (!stripe) stripe = Stripe(STRIPE_PK);
elements = stripe.elements({ clientSecret: data.client_secret, appearance: appearance() });
paymentEl = elements.create('payment', {
fields: { billingDetails: { name: 'never', email: 'never' } }
});
paymentEl.mount('#payment-element');
paymentEl.on('ready', function() {
var ld = document.querySelector('.checkout-element-loading');
if (ld) ld.remove();
if (submitBtn) submitBtn.disabled = false;
});
});
})
.catch(function() {
showMessage('Unable to connect. Please check your connection and try again.');
});
}
fetchAndMount();
var tNow = document.getElementById('timing-now');
var tLater = document.getElementById('timing-later');
if (tNow) tNow.addEventListener('change', fetchAndMount);
if (tLater) tLater.addEventListener('change', fetchAndMount);
var form = document.getElementById('payment-form');
if (form) form.addEventListener('submit', async function(e) {
e.preventDefault();
if (!stripe || !elements) return;
var attestCb = document.getElementById('founding-attest-cb');
if (attestCb && !attestCb.checked) {
var warn = document.getElementById('attest-warn');
if (warn) warn.style.display = 'block';
attestCb.closest('label').scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
var name = document.getElementById('buyer-name').value.trim();
var email = document.getElementById('buyer-email').value.trim();
if (!name || !email) { showMessage('Please enter your name and email.'); return; }
if (attestCb) {
try {
await fetch('/api/attest', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
plan: PLAN, name: name, email: email,
timestamp: new Date().toISOString(),
attestation: 'I am joining as a genuine early user, not to extract proprietary information about Neuron technology, architecture, or roadmap. I will engage in good faith. I understand that if this is not my intent, a different plan is a better fit.',
user_agent: navigator.userAgent
})
});
} catch(e) {}
}
setLoading(true);
var pmsg = document.getElementById('payment-message');
if (pmsg) pmsg.style.display = 'none';
if (window._neuronPiId) {
try {
await fetch('/api/link-customer', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
pi_id: window._neuronPiId,
email: email,
name: name,
plan: PLAN,
timing: currentTiming(),
mode: window._neuronMode || 'payment',
supabase_user_id: window._neuronSupaId || ''
})
});
} catch(e) {}
}
var confirmParams = {
return_url: window.location.origin + '/account?welcome=1',
payment_method_data: { billing_details: { name: name, email: email } }
};
var result;
if (window._neuronMode === 'setup') {
result = await stripe.confirmSetup({ elements: elements, confirmParams: confirmParams });
} else {
confirmParams.receipt_email = email;
result = await stripe.confirmPayment({ elements: elements, confirmParams: confirmParams });
}
if (result.error) {
showMessage(result.error.message || (window._neuronMode === 'setup'
? 'Could not save your card. Please try again.'
: 'Payment failed. Please try again.'));
setLoading(false);
}
});
})()")
}
+66
View File
@@ -0,0 +1,66 @@
// enterprise.el -- Enterprise inquiry form submission and headcount filter.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Exposed globals: entHeadcountChange(val)
fn main() -> Void {
native_js("(function() {
var form = document.getElementById('enterprise-form');
var submitBtn = document.getElementById('ent-submit');
var successDiv = document.getElementById('enterprise-success');
var errorDiv = document.getElementById('ent-form-error');
if (!form) return;
window.entHeadcountChange = function(val) {
var msgSecondary = document.getElementById('ent-filter-msg-secondary');
var msgYes = document.getElementById('ent-filter-msg-yes');
if (msgSecondary) msgSecondary.style.display = val === 'secondary' ? 'block' : 'none';
if (msgYes) msgYes.style.display = val === 'yes' ? 'block' : 'none';
if (submitBtn) {
submitBtn.disabled = val === 'yes';
submitBtn.style.opacity = val === 'yes' ? '0.35' : '1';
submitBtn.style.cursor = val === 'yes' ? 'not-allowed' : 'pointer';
}
};
form.addEventListener('submit', function(e) {
e.preventDefault();
var headcount = document.getElementById('ent-headcount').value;
if (headcount === 'yes') {
var msgYes = document.getElementById('ent-filter-msg-yes');
if (msgYes) msgYes.style.display = 'block';
return;
}
var name = document.getElementById('ent-name').value.trim();
var email = document.getElementById('ent-email').value.trim();
var company = document.getElementById('ent-company').value.trim();
var size = document.getElementById('ent-size').value;
var useCase = document.getElementById('ent-use').value.trim();
if (!name || !email || !company || !size || !useCase || !headcount) {
if (errorDiv) { errorDiv.textContent = 'Please fill out all fields.'; errorDiv.style.display = 'block'; }
return;
}
if (errorDiv) errorDiv.style.display = 'none';
if (submitBtn) { submitBtn.textContent = 'Sending...'; submitBtn.disabled = true; }
fetch('/api/enterprise-inquiry', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ name: name, email: email, company: company, size: size, use_case: useCase, headcount: headcount })
})
.then(function(r) { return r.json(); })
.then(function() {
if (form) form.style.display = 'none';
if (successDiv) successDiv.style.display = 'block';
})
.catch(function() {
if (submitBtn) { submitBtn.textContent = 'Send inquiry →'; submitBtn.disabled = false; }
if (errorDiv) { errorDiv.textContent = 'Something went wrong. Email enterprise@neurontechnologies.ai directly.'; errorDiv.style.display = 'block'; }
});
});
})()")
}
+19
View File
@@ -0,0 +1,19 @@
// environmental.el -- Environmental page efficiency calculator slider.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
var slider = document.getElementById('calc-slider');
var spendEl = document.getElementById('calc-spend');
var savingsEl = document.getElementById('calc-savings');
if (!slider) return;
function update() {
var monthly = parseInt(slider.value, 10);
var annual = Math.round(monthly * 0.35 * 12);
if (spendEl) spendEl.textContent = '$' + monthly;
if (savingsEl) savingsEl.textContent = '$' + annual;
}
slider.addEventListener('input', update);
update();
})()")
}
+186
View File
@@ -0,0 +1,186 @@
// gallery.el -- Gallery page: search/filter, sort, nav scroll, Supabase voting.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Required globals: window.NEURON_CFG.supabase_url, window.NEURON_CFG.supabase_anon_key
// Required CDN: supabase-js@2
fn main() -> Void {
native_js("(function() {
// Nav scroll effect
var nav = document.getElementById('nav');
if (nav) window.addEventListener('scroll', function() {
nav.classList.toggle('scrolled', window.scrollY > 10);
}, { passive: true });
// Hamburger
var btn = document.getElementById('nav-hamburger');
var menu = document.getElementById('nav-mobile');
if (btn && menu) {
function navClose() { menu.classList.remove('open'); btn.setAttribute('aria-expanded','false'); }
function navOpen() { menu.classList.add('open'); btn.setAttribute('aria-expanded','true'); }
btn.addEventListener('click', function(e) { e.stopPropagation(); menu.classList.contains('open') ? navClose() : navOpen(); });
menu.querySelectorAll('a').forEach(function(a) { a.addEventListener('click', navClose); });
document.addEventListener('click', function(e) { if (!nav.contains(e.target)) navClose(); });
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') navClose(); });
window.addEventListener('resize', function() { if (window.innerWidth > 1060) navClose(); });
}
// Dropdown
var ddBtn = document.querySelector('.nav-dropdown-btn');
var dd = document.querySelector('.nav-dropdown');
if (ddBtn && dd) {
ddBtn.addEventListener('click', function(e) {
e.stopPropagation();
var isOpen = dd.classList.contains('open');
dd.classList.toggle('open');
ddBtn.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
});
dd.querySelectorAll('.nav-dropdown-item').forEach(function(a) { a.addEventListener('click', function() { dd.classList.remove('open'); }); });
document.addEventListener('click', function() { dd.classList.remove('open'); });
}
// Search
var searchEl = document.getElementById('gal-search');
var grid = document.getElementById('gallery-grid');
var noResults = document.getElementById('no-results');
function filterCards() {
var q = (searchEl ? searchEl.value : '').toLowerCase().trim();
var cards = grid ? grid.querySelectorAll('.gal-card') : [];
var visible = 0;
cards.forEach(function(c) {
var match = !q || c.textContent.toLowerCase().indexOf(q) !== -1;
c.classList.toggle('hidden', !match);
if (match) visible++;
});
if (noResults) noResults.style.display = visible === 0 && q ? 'block' : 'none';
}
if (searchEl) searchEl.addEventListener('input', filterCards);
// Sort
window.setSort = function(mode, btn) {
document.querySelectorAll('.sort-btn').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
if (!grid) return;
var cards = Array.from(grid.querySelectorAll('.gal-card'));
cards.sort(function(a, b) {
if (mode === 'top') {
return parseInt(b.getAttribute('data-score') || '0') - parseInt(a.getAttribute('data-score') || '0');
} else {
return parseInt(b.getAttribute('data-ts') || '0') - parseInt(a.getAttribute('data-ts') || '0');
}
});
cards.forEach(function(c) { grid.appendChild(c); });
};
// Voting via Supabase
var cfg = window.NEURON_CFG || {};
var sbUrl = cfg.supabase_url;
var sbKey = cfg.supabase_anon_key;
if (!sbUrl || !sbKey) return;
var sb = window.supabase.createClient(sbUrl, sbKey);
var token = null;
var votes = {};
function getCtrl(sid) {
var found = null;
document.querySelectorAll('.vote-controls').forEach(function(c) {
if (c.getAttribute('data-share-id') === sid) found = c;
});
return found;
}
function applyState(ctrl, state) {
var sid = ctrl.getAttribute('data-share-id');
votes[sid] = state.user_vote || 'none';
var scoreEl = ctrl.querySelector('.vote-score');
if (scoreEl && state.score != null) scoreEl.textContent = state.score;
var upBtn = ctrl.querySelector('.vote-btn.vote-up');
var dnBtn = ctrl.querySelector('.vote-btn.vote-down');
if (upBtn) { upBtn.disabled = false; upBtn.classList.toggle('is-active', state.user_vote === 'up'); }
if (dnBtn) { dnBtn.disabled = false; dnBtn.classList.toggle('is-active', state.user_vote === 'down'); }
}
function loadVoteState(sid) {
var url = '/api/vote-state/' + sid;
if (token) url += '?access_token=' + encodeURIComponent(token);
fetch(url).then(function(r) { return r.json(); }).then(function(d) {
var ctrl = getCtrl(sid);
if (ctrl) applyState(ctrl, d);
}).catch(function() {});
}
function loadAll() {
document.querySelectorAll('.vote-controls').forEach(function(ctrl) {
var id = ctrl.getAttribute('data-share-id');
if (id) loadVoteState(id);
});
}
function castVote(sid, direction) {
if (!token) { showSignIn(); return; }
var ctrl = getCtrl(sid);
var btns = ctrl ? ctrl.querySelectorAll('.vote-btn') : [];
btns.forEach(function(b) { b.disabled = true; b.classList.add('is-loading'); });
fetch('/api/vote', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({access_token: token, id: sid, direction: direction})
}).then(function(r) { return r.json(); }).then(function(d) {
if (ctrl && d.ok) applyState(ctrl, d);
btns.forEach(function(b) { b.disabled = false; b.classList.remove('is-loading'); });
}).catch(function() {
btns.forEach(function(b) { b.disabled = false; b.classList.remove('is-loading'); });
});
}
document.querySelectorAll('.vote-controls').forEach(function(ctrl) {
ctrl.querySelectorAll('.vote-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var sid = ctrl.getAttribute('data-share-id');
if (!token) { showSignIn(); return; }
var dir = btn.getAttribute('data-direction');
var cur = votes[sid] || 'none';
castVote(sid, cur === dir ? 'none' : dir);
});
});
});
var modal = document.getElementById('signin-modal');
var cancelEl = document.getElementById('signin-cancel');
var sendEl = document.getElementById('signin-send');
var emailEl = document.getElementById('signin-email');
var msgEl = document.getElementById('signin-msg');
function showSignIn() { if (modal) modal.classList.add('open'); if (emailEl) emailEl.focus(); }
if (cancelEl) cancelEl.addEventListener('click', function() { modal.classList.remove('open'); });
if (modal) modal.addEventListener('click', function(e) { if (e.target === modal) modal.classList.remove('open'); });
if (sendEl) sendEl.addEventListener('click', function() {
var email = emailEl ? emailEl.value.trim() : '';
if (!email) { if (msgEl) msgEl.textContent = 'Please enter your email.'; return; }
sendEl.disabled = true;
if (msgEl) msgEl.textContent = 'Sending...';
sb.auth.signInWithOtp({ email: email, options: { emailRedirectTo: window.location.href } })
.then(function(r) {
sendEl.disabled = false;
if (msgEl) msgEl.textContent = r.error
? (r.error.message || 'Error. Try again.')
: 'Check your email for a sign-in link.';
});
});
if (emailEl) emailEl.addEventListener('keydown', function(e) { if (e.key === 'Enter' && sendEl) sendEl.click(); });
sb.auth.onAuthStateChange(function(event, session) {
token = session ? session.access_token : null;
if (token && modal) modal.classList.remove('open');
loadAll();
});
sb.auth.getSession().then(function(r) {
token = r.data && r.data.session ? r.data.session.access_token : null;
loadAll();
});
})()")
}
+67
View File
@@ -0,0 +1,67 @@
// main.el -- Share page voting, copy-for-platform social sharing.
// Compiled with: elc --target=js --bundle --minify --obfuscate
//
// Required globals: window.NEURON_CFG.id, window.NEURON_CFG.card_url
// Exposed globals: copyForPlatform(platform, btn)
fn main() -> Void {
native_js("(function() {
var cfg = window.NEURON_CFG || {};
var shareId = cfg.id || '';
var cardUrl = cfg.card_url || '';
// Copy-for-platform: format and copy share text for different social platforms
window.copyForPlatform = function(platform, btn) {
var text = '';
var url = window.location.href;
if (platform === 'tiktok') {
text = 'Neuron said something interesting. Watch this. ' + url;
} else if (platform === 'snapchat') {
text = url;
} else {
text = url;
}
navigator.clipboard.writeText(text).then(function() {
if (btn) {
btn.classList.add('copied');
setTimeout(function() { btn.classList.remove('copied'); }, 1500);
}
}).catch(function() {});
};
// Vote buttons on share page
var voteUp = document.getElementById('vote-up');
var voteDown = document.getElementById('vote-down');
var voteScore = document.getElementById('vote-score');
var voted = null;
function updateVoteUI(direction, score) {
if (voteUp) voteUp.classList.toggle('voted-up', direction === 'up');
if (voteDown) voteDown.classList.toggle('voted-down', direction === 'down');
if (voteScore && score != null) voteScore.textContent = score;
}
function castVote(direction) {
var next = voted === direction ? 'none' : direction;
voted = next === 'none' ? null : next;
fetch('/api/vote', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ id: shareId, direction: next })
}).then(function(r) { return r.json(); }).then(function(d) {
if (d.ok) updateVoteUI(next === 'none' ? null : next, d.score);
}).catch(function() {});
}
if (voteUp) voteUp.addEventListener('click', function() { castVote('up'); });
if (voteDown) voteDown.addEventListener('click', function() { castVote('down'); });
// Load initial vote state
if (shareId) {
fetch('/api/vote-state/' + shareId)
.then(function(r) { return r.json(); })
.then(function(d) { updateVoteUI(d.user_vote || null, d.score); })
.catch(function() {});
}
})()")
}
+42
View File
@@ -0,0 +1,42 @@
// marketplace.el -- Marketplace developer interest form submission.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
var form = document.getElementById('dev-form');
if (!form) return;
form.addEventListener('submit', async function(e) {
e.preventDefault();
var msg = document.getElementById('dev-msg');
var btn = form.querySelector('button[type=submit]');
btn.disabled = true;
btn.textContent = 'Sending...';
try {
var r = await fetch('/api/developer-interest', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: document.getElementById('dev-name').value,
email: document.getElementById('dev-email').value,
idea: document.getElementById('dev-idea').value
})
});
msg.style.display = 'block';
if (r.ok) {
msg.textContent = 'Got it. Will review it personally and reach out.';
msg.style.color = 'var(--navy)';
form.reset();
} else {
msg.textContent = 'Something went wrong. Email developers@neurontechnologies.ai directly.';
msg.style.color = '#c44';
}
} catch(err) {
msg.style.display = 'block';
msg.textContent = 'Connection error. Email developers@neurontechnologies.ai directly.';
msg.style.color = '#c44';
}
btn.disabled = false;
btn.textContent = 'Send interest →';
});
})()")
}
+56
View File
@@ -0,0 +1,56 @@
// nav.el -- Navigation hamburger menu and Mission dropdown.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
var btn = document.getElementById('nav-hamburger');
var menu = document.getElementById('nav-mobile');
var nav = document.getElementById('nav');
if (!btn || !menu) return;
function close() {
menu.classList.remove('open');
btn.setAttribute('aria-expanded', 'false');
}
function open() {
menu.classList.add('open');
btn.setAttribute('aria-expanded', 'true');
}
function toggle() {
if (menu.classList.contains('open')) { close(); } else { open(); }
}
btn.addEventListener('click', function(e) { e.stopPropagation(); toggle(); });
var ddBtn = document.querySelector('.nav-dropdown-btn');
var dd = document.querySelector('.nav-dropdown');
if (ddBtn && dd) {
ddBtn.addEventListener('click', function(e) {
e.stopPropagation();
var isOpen = dd.classList.contains('open');
dd.classList.toggle('open');
ddBtn.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
});
dd.querySelectorAll('.nav-dropdown-item').forEach(function(a) {
a.addEventListener('click', function() { dd.classList.remove('open'); });
});
document.addEventListener('click', function() { dd.classList.remove('open'); });
}
menu.querySelectorAll('a').forEach(function(a) {
a.addEventListener('click', close);
});
document.addEventListener('click', function(e) {
if (!nav.contains(e.target)) { close(); }
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { close(); }
});
window.addEventListener('resize', function() {
if (window.innerWidth > 1060) { close(); }
});
})()")
}
+99
View File
@@ -0,0 +1,99 @@
// styles.el -- Landing page JS: nav scroll, scroll-reveal, founding counter polling,
// checkout button routing.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
'use strict';
// Nav scroll effect
var nav = document.getElementById('nav');
if (nav) {
window.addEventListener('scroll', function() {
if (window.scrollY > 40) {
nav.classList.add('scrolled');
} else {
nav.classList.remove('scrolled');
}
}, { passive: true });
}
// Auto-open chat if ?open=chat in URL
if (typeof URLSearchParams !== 'undefined' && new URLSearchParams(window.location.search).get('open') === 'chat') {
setTimeout(function() { if (typeof neuronDemoToggle === 'function') neuronDemoToggle(); }, 600);
}
// Scroll reveal via IntersectionObserver
var revealEls = document.querySelectorAll('.reveal');
if ('IntersectionObserver' in window) {
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
revealEls.forEach(function(el) { observer.observe(el); });
} else {
revealEls.forEach(function(el) { el.classList.add('visible'); });
}
// Founding counter polling
var prevSold = null;
function updateFoundingUI(data) {
var remaining = data.remaining;
var sold = data.sold;
var total = data.total;
var pct = Math.round((sold / total) * 100);
var flash = prevSold !== null && sold > prevSold;
prevSold = sold;
var spotLabel = document.querySelector('.founding-spots-label');
if (spotLabel) spotLabel.textContent = 'Only ' + remaining + ' left';
var spotFill = document.querySelector('.founding-spots-fill');
if (spotFill) spotFill.style.width = pct + '%';
var spotSub = document.querySelector('.founding-spots-sub');
if (spotSub) spotSub.textContent = sold + ' of ' + total + ' claimed';
var bannerCount = document.querySelector('.founding-banner-count');
if (bannerCount) {
bannerCount.textContent = remaining;
if (flash) {
bannerCount.style.color = '#0078D4';
setTimeout(function() { bannerCount.style.color = ''; }, 1200);
}
}
var bannerFill = document.querySelector('.founding-banner-fill');
if (bannerFill) bannerFill.style.width = pct + '%';
}
function pollFoundingCount() {
fetch('/api/founding-count')
.then(function(r) { return r.json(); })
.then(function(data) { updateFoundingUI(data); })
.catch(function() {});
}
pollFoundingCount();
setInterval(pollFoundingCount, 90000);
// Hide chat widget on non-marketing pages
if (window.location.pathname.indexOf('/checkout') === 0 ||
window.location.pathname.indexOf('/account') === 0 ||
window.location.pathname.indexOf('/legal') === 0 ||
window.location.pathname.indexOf('/marketplace/success') === 0) {
var demoBtn = document.getElementById('neuron-demo-btn');
var demoPanel = document.getElementById('neuron-demo-panel');
if (demoBtn) demoBtn.style.display = 'none';
if (demoPanel) demoPanel.style.display = 'none';
}
// Checkout buttons
var checkoutBtns = document.querySelectorAll('[data-checkout]');
checkoutBtns.forEach(function(btn) {
btn.addEventListener('click', function() {
window.location.href = '/checkout?plan=' + btn.getAttribute('data-checkout');
});
});
})()")
}