PageSourceSearch

https://www.bigibyte.com/assets/contact.js

js bigibyte.com collected 2026-10-02 01:24:19 UTC 3,594 bytes, 45 lines download raw bytes

1// Contact page: interactive project brief + mobile quick-contact dock.
2(function () {
3  var form = document.querySelector('form[data-brief]');
4  if (form) {
5    var chips = form.querySelectorAll('.cf-chip'), segs = form.querySelectorAll('.cf-seg');
6    var bar = form.querySelector('.cf-bar i'), pct = form.querySelector('.cf-pct');
7    var note = form.querySelector('.cf-note'), btn = form.querySelector('.cf-send');
8    var f = function (n) { return form.querySelector('[name=' + n + ']'); };
9    var picked = function (list) { return [].filter.call(list, function (b) { return b.getAttribute('aria-pressed') === 'true'; }).map(function (b) { return b.getAttribute('data-v') || b.textContent; }); };
10    var progress = function () {
11      var done = [f('name').value.trim(), /\S+@\S+\.\S+/.test(f('email').value), picked(chips).length, f('message').value.trim().length > 15].filter(Boolean).length;
12      var p = Math.round(done / 4 * 100);
13      bar.style.width = p + '%';
14      pct.textContent = p === 100 ? 'Ready to send' : p + '% complete';
15      pct.classList.toggle('cf-ready', p === 100);
16    };
17    chips.forEach(function (b) { b.addEventListener('click', function () { b.setAttribute('aria-pressed', b.getAttribute('aria-pressed') === 'true' ? 'false' : 'true'); progress(); }); });
18    segs.forEach(function (b) { b.addEventListener('click', function () { segs.forEach(function (x) { x.setAttribute('aria-pressed', x === b ? 'true' : 'false'); }); }); });
19    form.addEventListener('input', progress);
20    form.addEventListener('submit', function (e) {
21      e.preventDefault();
22      var bad = null;
23      ['name', 'email', 'message'].forEach(function (n) {
24        var el = f(n), ok = n === 'email' ? /\S+@\S+\.\S+/.test(el.value) : el.value.trim().length > 0;
25        el.closest('.cf-field').classList.toggle('cf-err', !ok);
26        if (!ok && !bad) bad = el;
27      });
28      if (bad) { bad.focus(); note.className = 'cf-note cf-bad'; note.textContent = 'Please add your name, a valid email and a few words about the project.'; return; }
29      var needs = picked(chips), budget = picked(segs)[0] || '';
30      var msg = f('message').value.trim();
31      btn.disabled = true; btn.classList.add('cf-busy'); note.className = 'cf-note'; note.textContent = 'Sending your brief...';
32      fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: f('name').value.trim(), email: f('email').value.trim(), phone: f('phone').value.trim(), subject: 'Website brief: ' + (needs.join(', ') || 'New project') + (budget ? ' (' + budget + ')' : ''), message: msg, needs: needs, budget: budget, page: location.href, website: f('website').value }) })
33        .then(function (r) { return r.json().catch(function () { return {}; }).then(function (d) { if (!r.ok || !d.ok) throw new Error(); }); })
34        .then(function () { form.classList.add('cf-sent'); form.querySelector('.cf-done').hidden = false; })
35        .catch(function () { note.className = 'cf-note cf-bad'; note.textContent = 'We could not send your brief. Please try again, or email [email protected].'; })
36        .finally(function () { btn.disabled = false; btn.classList.remove('cf-busy'); });
37    });
38    progress();
39  }
40  // Mobile quick-contact dock: show once the hero is scrolled past.
41  var dock = document.querySelector('.ct-dock'), hero = document.querySelector('.ct-hero');
42  if (dock && hero && 'IntersectionObserver' in window) {
43    new IntersectionObserver(function (e) { dock.classList.toggle('ct-dock-on', !e[0].isIntersecting); }).observe(hero);
44  }
45})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.