1
0
forked from jason/scj
Files
Jason Stedwell cf9f9c5f1a form submission
2026-06-30 22:49:30 -05:00

219 lines
8.3 KiB
JavaScript
Raw Permalink 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.
/* ============================================================
Storm Cloud Jumpers — site interactions
============================================================ */
(function () {
'use strict';
/* ----------------------------------------------------------
FORM DELIVERY CONFIG
------------------------------------------------------------
By default the inquiry form opens the visitor's email app
addressed to Storm Cloud Jumpers (mailto:). No server needed.
To have submissions land straight in the Gmail inbox WITHOUT
the visitor needing a mail app, deploy the included
`form-handler.gs` as a Google Apps Script web app (it sends
from the shop's own Gmail) and paste its /exec URL below.
When FORM_ENDPOINT is set, the form POSTs to it and falls
back to mailto only if the request fails.
---------------------------------------------------------- */
var CONTACT_EMAIL = 'stormcloudjumpers@gmail.com';
var FORM_ENDPOINT = 'https://script.google.com/macros/s/AKfycbzwcGznA_bTggaE1xxqNh0DY0yBJnDJ5ZbZp8uw4lVcYWaxvfZorKAHgNw0hdzxtWljOA/exec';
var $ = function (s, c) { return (c || document).querySelector(s); };
var $$ = function (s, c) { return Array.prototype.slice.call((c || document).querySelectorAll(s)); };
/* ---------- Sticky nav shadow ---------- */
var nav = $('#nav');
var onScroll = function () {
if (nav) nav.classList.toggle('scrolled', window.scrollY > 12);
};
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
/* ---------- Mobile menu ---------- */
var burger = $('#burger');
var links = $('#navLinks');
var closeMenu = function () {
if (!links) return;
links.classList.remove('open');
nav.classList.remove('menu-open');
burger.setAttribute('aria-expanded', 'false');
};
if (burger && links) {
burger.addEventListener('click', function () {
var open = links.classList.toggle('open');
nav.classList.toggle('menu-open', open);
burger.setAttribute('aria-expanded', String(open));
});
$$('a', links).forEach(function (a) { a.addEventListener('click', closeMenu); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeMenu(); });
}
/* ---------- Reveal on scroll ---------- */
var reveals = $$('.reveal');
if ('IntersectionObserver' in window && reveals.length) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting) { en.target.classList.add('in'); io.unobserve(en.target); }
});
}, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add('in'); });
}
/* ---------- Hero parallax (subtle, respects reduced motion) ---------- */
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var heroBg = $('.hero__bg');
if (heroBg && !reduce) {
window.addEventListener('scroll', function () {
var y = window.scrollY;
if (y < window.innerHeight) heroBg.style.transform = 'translateY(' + (y * 0.25) + 'px)';
}, { passive: true });
}
/* ---------- "Reserve" buttons prefill the spider field ---------- */
$$('[data-inquire]').forEach(function (btn) {
btn.addEventListener('click', function () {
var field = $('#spiderField');
if (field) field.value = btn.getAttribute('data-inquire') || '';
});
});
/* ---------- Inquiry form ---------- */
var form = $('#inquiryForm');
var ok = $('#formOk');
var buildMailto = function (data) {
var subjSpider = data.spider ? ' — ' + data.spider : '';
var subject = 'Spider Inquiry' + subjSpider + ' (' + data.name + ')';
var body =
'Name: ' + data.name + '\n' +
'Email: ' + data.email + '\n' +
'Spider of interest: ' + (data.spider || '(not specified)') + '\n\n' +
'Message:\n' + (data.message || '(none)') + '\n';
return 'mailto:' + CONTACT_EMAIL +
'?subject=' + encodeURIComponent(subject) +
'&body=' + encodeURIComponent(body);
};
if (form) {
form.addEventListener('submit', function (e) {
e.preventDefault();
if (!form.checkValidity()) { form.reportValidity(); return; }
var data = {
name: form.name.value.trim(),
email: form.email.value.trim(),
spider: form.spider.value.trim(),
message: form.message.value.trim()
};
var finishMailto = function () {
window.location.href = buildMailto(data);
if (ok) ok.hidden = false;
};
if (FORM_ENDPOINT) {
// Progressive enhancement: POST to Google Apps Script (sends via her Gmail).
// Apps Script web apps don't send CORS headers, so we use no-cors and
// treat a resolved request as success (the opaque response can't be read).
// A genuine network failure rejects and falls back to mailto.
var btn = form.querySelector('button[type="submit"]');
if (btn) { btn.disabled = true; btn.textContent = 'Sending…'; }
fetch(FORM_ENDPOINT, {
method: 'POST',
mode: 'no-cors',
body: new URLSearchParams(data)
}).then(function () {
if (ok) {
ok.className = 'form__msg form__msg--ok';
ok.textContent = 'Thanks! Your inquiry has been sent — well reply within a day or two.';
ok.hidden = false;
}
form.reset();
}).catch(finishMailto).then(function () {
if (btn) { btn.disabled = false; btn.textContent = 'Send Inquiry'; }
});
} else {
finishMailto();
}
});
}
/* ---------- Mamas lightbox ---------- */
var lb = $('#lightbox');
var lbImg = $('#lightboxImg');
var lbCap = $('#lightboxCap');
var lbClose = $('#lightboxClose');
var lastFocused = null;
var openLightbox = function (trigger, img, capHTML) {
if (!img || !lb) return;
lastFocused = trigger;
lbImg.src = img.getAttribute('src');
lbImg.alt = img.getAttribute('alt') || '';
lbCap.innerHTML = capHTML || '';
lb.hidden = false;
requestAnimationFrame(function () { lb.classList.add('open'); });
document.body.style.overflow = 'hidden';
lbClose.focus();
};
var wireZoom = function (trigger, getImg, getCap, label) {
trigger.setAttribute('role', 'button');
trigger.setAttribute('tabindex', '0');
trigger.setAttribute('aria-label', label);
var open = function () { openLightbox(trigger, getImg(), getCap()); };
trigger.addEventListener('click', open);
trigger.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); }
});
};
var closeLightbox = function () {
if (!lb || lb.hidden) return;
lb.classList.remove('open');
document.body.style.overflow = '';
var done = function () {
lb.hidden = true;
lbImg.src = '';
lb.removeEventListener('transitionend', done);
if (lastFocused && lastFocused.focus) lastFocused.focus();
};
if (reduce) { done(); } else { lb.addEventListener('transitionend', done); }
};
if (lb) {
// Meet the Mamas gallery
$$('.mama').forEach(function (fig) {
var name = $('.mama__cap b', fig);
wireZoom(fig,
function () { return $('img', fig); },
function () { var c = $('.mama__cap', fig); return c ? c.innerHTML : ''; },
'Enlarge photo' + (name ? ' of ' + name.textContent : ''));
});
// Available spiders — click the photo to enlarge
$$('#available .card__media').forEach(function (media) {
var card = media.closest('.card');
wireZoom(media,
function () { return $('img', media); },
function () {
var h = $('h3', card), sci = $('.card__sci', card);
return (h ? '<b>' + h.textContent + '</b>' : '') + (sci ? '<span>' + sci.textContent + '</span>' : '');
},
'Enlarge photo' + (card && $('h3', card) ? ' of ' + $('h3', card).textContent : ''));
});
lbClose.addEventListener('click', closeLightbox);
lb.addEventListener('click', function (e) { if (e.target === lb) closeLightbox(); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeLightbox(); });
}
/* ---------- Footer year ---------- */
var y = $('#year');
if (y) y.textContent = String(new Date().getFullYear());
})();