Custom team stores
Your own team store.
We build a private online store just for your team, with your logo and colors on the full KitBeast lineup. Parents and fans open it with your password and order what they want. You send one request. We approve it with you and handle the build.
Your logo and colors on every product Private and password-only, so just your people get in 30+ products: uniforms, hoodies, bags, accessories and more
kitbeastapparel.com/store/east-county-elite-preview
Preview a team store Watch a finished store, exactly as parents see it
Pick a color ×
It does not need to be exact. A close color is all we need.
# Add
Common team colors
← Back
kitbeastapparel.com/store/east-county-elite-preview
Preview
Thank you for choosing KitBeast
You're in.Request sent.
Congratulations! You submitted a request. A KitBeast team rep will be in touch to approve your team store request and start designing your team store for you.
Under 10 minutes, a team rep will reach out
What happens next
1 We approve it Your rep confirms your products, logo and colors with you.
2 Your store goes live We build it and send you the link and password.
3 People order Share the link. People enter the password and can buy whatever they want.
Want to talk sooner? Call or text us any time.332-318-2729
Back to home
10 * 1024 * 1024) { showErr('"' + f.name + '" is over 10MB. Try a smaller file, or send it to your rep.'); return; } files.push(f); }); drawFiles(); }
function drawFiles() { var ul = q('[data-kts-files]'); ul.innerHTML = ''; files.forEach(function (f, i) { var li = document.createElement('li'); li.textContent = f.name; var x = document.createElement('button'); x.type = 'button'; x.innerHTML = '×'; x.setAttribute('aria-label', 'Remove'); x.addEventListener('click', function () { files.splice(i, 1); drawFiles(); }); li.appendChild(x); ul.appendChild(li); }); }
fileIn.addEventListener('change', function () { addFiles(fileIn.files); fileIn.value = ''; });
['dragover', 'dragenter'].forEach(function (ev) { drop.addEventListener(ev, function (e) { e.preventDefault(); drop.classList.add('is-over'); }); });
['dragleave', 'drop'].forEach(function (ev) { drop.addEventListener(ev, function (e) { e.preventDefault(); drop.classList.remove('is-over'); if (ev === 'drop' && e.dataTransfer) addFiles(e.dataTransfer.files); }); });
/* colors: same picker and presets as the design process */
var PRESETS = ['#000000', '#FFFFFF', '#CC0000', '#003087', '#005EB8', '#009A44', '#FFB81C', '#FF6600', '#5C068C', '#6F263D', '#69B3E7', '#215732', '#FF1493', '#008B8B', '#808080', '#CC4400', '#D4AF37', '#1D428A'];
var sw = q('[data-kts-sw]');
function addColor(hex) { hex = hex.toLowerCase(); var i = colors.findIndex(function (c) { return c.hex === hex; }); if (i > -1) colors.splice(i, 1); else colors.push({ name: hex.toUpperCase(), hex: hex }); drawColors(); }
function drawColors() { qa('.kts-sw[data-hex]').forEach(function (b) { b.classList.toggle('is-on', colors.some(function (c) { return c.hex === b.getAttribute('data-hex'); })); }); var p = q('[data-kts-picked]'); p.innerHTML = ''; colors.forEach(function (c) { var s = document.createElement('span'), i = document.createElement('i'); i.style.background = c.hex; s.appendChild(i); s.appendChild(document.createTextNode(c.name)); var x = document.createElement('button'); x.type = 'button'; x.innerHTML = '×'; x.setAttribute('aria-label', 'Remove'); x.addEventListener('click', function () { addColor(c.hex); }); s.appendChild(x); p.appendChild(s); }); }
PRESETS.forEach(function (hex) { var b = document.createElement('button'); b.type = 'button'; b.className = 'kts-sw'; b.style.background = hex; b.setAttribute('data-hex', hex.toLowerCase()); b.setAttribute('aria-label', hex); b.addEventListener('click', function () { addColor(hex); }); sw.appendChild(b); });
var plus = document.createElement('button'); plus.type = 'button'; plus.className = 'kts-sw kts-sw--plus'; plus.setAttribute('aria-label', 'Pick any color'); plus.title = 'Pick any color'; sw.appendChild(plus);
// the color field + hue slider
var cp = q('[data-kts-cp]'), cpov = q('[data-kts-cpov]'), svc = q('#kts-cp-sv'), huec = q('#kts-cp-hue'), hexIn = q('[data-kts-cphex]'), prev = q('[data-kts-cpprev]');
var H = 210, S = 0.75, V = 0.9, dragSV = false, dragH = false, svx, hux;
function hsv2hex(h, s, v) { var r, g, b, i = Math.floor(h / 60) % 6, f = h / 60 - Math.floor(h / 60), p = v * (1 - s), qq = v * (1 - f * s), t = v * (1 - (1 - f) * s); switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = qq; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = qq; b = v; break; case 4: r = t; g = p; b = v; break; default: r = v; g = p; b = qq; } return [r, g, b].map(function (x) { return ('0' + Math.round(x * 255).toString(16)).slice(-2); }).join(''); }
function hex2hsv(hex) { if (hex.length === 3) hex = hex.replace(/./g, '$&$&'); if (hex.length !== 6) return null; var r = parseInt(hex.slice(0, 2), 16) / 255, g = parseInt(hex.slice(2, 4), 16) / 255, b = parseInt(hex.slice(4, 6), 16) / 255, mx = Math.max(r, g, b), mn = Math.min(r, g, b), d = mx - mn, h = 0; if (d) { if (mx === r) h = ((g - b) / d) % 6; else if (mx === g) h = (b - r) / d + 2; else h = (r - g) / d + 4; h *= 60; if (h < 0) h += 360; } return { h: h, s: mx ? d / mx : 0, v: mx }; }
function drawSV() { var w = svc.width, h = svc.height; svx.clearRect(0, 0, w, h); svx.fillStyle = 'hsl(' + H + ',100%,50%)'; svx.fillRect(0, 0, w, h); var gw = svx.createLinearGradient(0, 0, w, 0); gw.addColorStop(0, '#fff'); gw.addColorStop(1, 'rgba(255,255,255,0)'); svx.fillStyle = gw; svx.fillRect(0, 0, w, h); var gb = svx.createLinearGradient(0, 0, 0, h); gb.addColorStop(0, 'rgba(0,0,0,0)'); gb.addColorStop(1, '#000'); svx.fillStyle = gb; svx.fillRect(0, 0, w, h); var x = S * w, y = (1 - V) * h; svx.beginPath(); svx.arc(x, y, 9, 0, 6.2832); svx.lineWidth = 3; svx.strokeStyle = '#fff'; svx.stroke(); svx.beginPath(); svx.arc(x, y, 10.5, 0, 6.2832); svx.lineWidth = 1; svx.strokeStyle = '#000'; svx.stroke(); }
function drawHue() { var w = huec.width, h = huec.height; hux.clearRect(0, 0, w, h); var g = hux.createLinearGradient(0, 0, w, 0); for (var i = 0; i <= 12; i++) g.addColorStop(i / 12, 'hsl(' + (i * 30) + ',100%,50%)'); hux.fillStyle = g; hux.fillRect(0, 0, w, h); var x = (H / 360) * w; hux.beginPath(); hux.arc(x, h / 2, h / 2 - 1, 0, 6.2832); hux.lineWidth = 3; hux.strokeStyle = '#fff'; hux.stroke(); }
function sync(fromHex) { var hex = hsv2hex(H, S, V); if (!fromHex) hexIn.value = hex; prev.style.background = '#' + hexIn.value.replace(/[^0-9a-f]/gi, '').padEnd(6, '0').slice(0, 6); if (!fromHex) prev.style.background = '#' + hex; drawSV(); drawHue(); }
function xy(e, c) { var r = c.getBoundingClientRect(), s = e.touches ? e.touches[0] : e; return { x: Math.max(0, Math.min(c.width, (s.clientX - r.left) * (c.width / r.width))), y: Math.max(0, Math.min(c.height, (s.clientY - r.top) * (c.height / r.height))) }; }
function openCP() { cp.classList.add('is-open'); cpov.classList.add('is-open'); setTimeout(function () { svc.width = svc.offsetWidth; svc.height = svc.offsetHeight; huec.width = huec.offsetWidth; huec.height = huec.offsetHeight; svx = svc.getContext('2d'); hux = huec.getContext('2d'); sync(false); }, 60); }
function closeCP() { cp.classList.remove('is-open'); cpov.classList.remove('is-open'); }
plus.addEventListener('click', openCP); cpov.addEventListener('click', closeCP); q('[data-kts-cpx]').addEventListener('click', closeCP); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeCP(); });
function svPick(e) { e.preventDefault(); var p = xy(e, svc); S = p.x / svc.width; V = 1 - p.y / svc.height; sync(false); }
function huePick(e) { e.preventDefault(); var p = xy(e, huec); H = Math.min(359.9, (p.x / huec.width) * 360); sync(false); }
svc.addEventListener('mousedown', function (e) { dragSV = true; svPick(e); }); svc.addEventListener('touchstart', function (e) { dragSV = true; svPick(e); }, { passive: false });
huec.addEventListener('mousedown', function (e) { dragH = true; huePick(e); }); huec.addEventListener('touchstart', function (e) { dragH = true; huePick(e); }, { passive: false });
document.addEventListener('mousemove', function (e) { if (dragSV) svPick(e); if (dragH) huePick(e); }); document.addEventListener('touchmove', function (e) { if (dragSV) svPick(e); if (dragH) huePick(e); }, { passive: false });
document.addEventListener('mouseup', function () { dragSV = dragH = false; }); document.addEventListener('touchend', function () { dragSV = dragH = false; });
hexIn.addEventListener('input', function () { var v = this.value.replace(/[^0-9a-fA-F]/g, ''); this.value = v; var c = hex2hsv(v); if (c) { H = c.h; S = c.s; V = c.v; sync(true); prev.style.background = '#' + (v.length === 3 ? v.replace(/./g, '$&$&') : v); } });
q('[data-kts-cpadd]').addEventListener('click', function () { var v = hexIn.value.trim().replace(/^#/, ''); if (v.length === 3) v = v.replace(/./g, '$&$&'); if (v.length !== 6) return; addColor('#' + v); closeCP(); });
hexIn.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); q('[data-kts-cpadd]').click(); } });
PRESETS.forEach(function (hex) { var b = document.createElement('button'); b.type = 'button'; b.style.background = hex; b.setAttribute('aria-label', hex); b.addEventListener('click', function () { addColor(hex); closeCP(); }); q('[data-kts-cppre]').appendChild(b); });
/* submit */
var errEl = q('[data-kts-error]');
function showErr(m) { errEl.textContent = m; errEl.hidden = false; }
function bad(k, on) { var e = q('[data-kts="' + k + '"]'); if (e) e.parentNode.classList.toggle('is-bad', on); }
function validate() {
var checks = { team: data('team').length >= 2, sport: !!data('sport'), players: +data('players') > 0, name: data('name').length >= 2, phone: data('phone').replace(/\D/g, '').length >= 7, email: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(data('email')), password: data('password').length >= 4 };
var first = null; Object.keys(checks).forEach(function (k) { bad(k, !checks[k]); if (!checks[k] && !first) first = k; });
if (first) { var e = q('[data-kts="' + first + '"]'); if (e) { e.scrollIntoView({ block: 'center', behavior: 'smooth' }); e.focus(); } showErr(first === 'password' ? 'Pick a store password (at least 4 characters) that parents will use to open the store.' : 'Please fill in the highlighted fields.'); return false; }
if (!files.length && !colors.length) { showErr('Add your logo or pick at least one team color.'); q('[data-kts-drop]').scrollIntoView({ block: 'center', behavior: 'smooth' }); return false; }
return true;
}
var OPS = 'https://kitbeast-ops-app.vercel.app', kbUp = [];
function uploadAll() { // logos go to the ops app (Team Store tab), not a third-party host
if (PREVIEW || !files.length) return Promise.resolve(files.map(function (f) { return f.name; }));
kbUp = [];
return Promise.all(files.map(function (f) { var fd = new FormData(); fd.append('file', f); return fetch(OPS + '/api/team-store-request/upload', { method: 'POST', body: fd }).then(function (r) { return r.json(); }).then(function (j) { if (j && j.url) { kbUp.push({ url: j.url, filename: j.filename || f.name }); return j.url; } return f.name + ' (upload failed)'; }).catch(function () { return f.name + ' (upload failed)'; }); }));
}
function showSum(lines) { // the recap card on the confirmation page: one tile per answer, colors as swatches
var box = q('[data-kts-sum]'); box.innerHTML = '';
var top = document.createElement('div'); top.className = 'kts-rc__top'; top.innerHTML = '
Your team store request RECEIVED '; box.appendChild(top);
var grid = document.createElement('div'); grid.className = 'kts-rc__grid'; box.appendChild(grid);
var keep = { 'Team': 'Team', 'Sport': 'Sport', 'Players': 'Players', 'Needed by': 'Needed by', 'Colors': 'Colors' };
lines.forEach(function (l) {
var i = l.indexOf(': '); if (i < 0) return; var k = l.slice(0, i), v = l.slice(i + 2); if (!keep[k] || !v) return;
var cell = document.createElement('div'); cell.className = 'kts-rc__cell' + (k === 'Colors' ? ' kts-rc__cell--wide' : '');
var kk = document.createElement('span'); kk.className = 'kts-rc__k'; kk.textContent = k; cell.appendChild(kk);
if (k === 'Colors' && v !== 'none picked') {
var sw = document.createElement('div'); sw.className = 'kts-rc__sw';
v.split(', ').forEach(function (c) { var m = c.match(/^(.*?)\s*(#[0-9a-fA-F]{3,6})$/); var chip = document.createElement('span'); var dot = document.createElement('b'); dot.style.background = m ? m[2] : '#888'; chip.appendChild(dot); chip.appendChild(document.createTextNode(m ? (m[1] || m[2]) : c)); sw.appendChild(chip); });
cell.appendChild(sw);
} else { var vv = document.createElement('span'); vv.className = 'kts-rc__v'; vv.textContent = v; cell.appendChild(vv); }
grid.appendChild(cell);
});
}
function summary(fileLinks) {
return { lines: ['Team: ' + data('team'), 'Sport: ' + data('sport'), 'Players: ' + data('players'), data('deadline') ? 'Needed by: ' + data('deadline') : '', 'Colors: ' + (colors.map(function (c) { return c.name + ' ' + c.hex; }).join(', ') || 'none picked'), 'Logo files: ' + (fileLinks.join(' | ') || 'none'), data('notes') ? 'Notes: ' + data('notes') : '', 'Requested store password: ' + data('password')].filter(Boolean) };
}
// draft-only bubble: jump straight to the confirmation page to look at it (sends nothing; never shows on the published theme)
try {
if (/[?&]kbeye\b/.test(location.search) && window.Shopify && Shopify.theme && Shopify.theme.role && Shopify.theme.role !== 'main') {
var pvb = document.createElement('button'); pvb.type = 'button'; pvb.textContent = '\u2705 Preview the "request sent" page';
pvb.style.cssText = 'position:fixed;left:14px;bottom:96px;z-index:2147483646;padding:10px 16px;border:1px solid #0a0a0a;border-radius:999px;background:#d1fa5f;color:#0a0a0a;cursor:pointer;box-shadow:0 6px 20px rgba(0,0,0,.25);font:700 12px Arial,sans-serif;';
document.body.appendChild(pvb);
pvb.addEventListener('click', function () {
showSum(['Team: East County Elite', 'Sport: Flag football', 'Players: 30', 'Needed by: Sept 12', 'Colors: Navy #0a1f44, Gold #d4a017']);
q('[data-kts-main]').hidden = true; q('[data-kts-done]').hidden = false; window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
} catch (e) {}
form.addEventListener('submit', function (e) {
e.preventDefault(); errEl.hidden = true;
if (!validate()) return;
var btn = q('[data-kts-submit]'), label = btn.textContent; btn.disabled = true; btn.textContent = 'Sending...';
uploadAll().then(function (links) {
var sum = summary(links);
var done = function () {
showSum(sum.lines);
q('[data-kts-main]').hidden = true; q('[data-kts-done]').hidden = false; window.scrollTo({ top: 0, behavior: 'smooth' });
try { var lead = JSON.parse(localStorage.getItem('kb_lead_v3') || '{}'); var nm = data('name').split(/\s+/); lead.first = lead.first || nm.shift() || ''; lead.last = lead.last || nm.join(' '); lead.email = lead.email || data('email'); lead.phone = lead.phone || data('phone'); localStorage.setItem('kb_lead_v3', JSON.stringify(lead)); } catch (er) {}
};
if (PREVIEW) { setTimeout(done, 700); return; }
q('[data-kts-h-name]').value = data('name'); q('[data-kts-h-email]').value = data('email'); q('[data-kts-h-phone]').value = data('phone');
q('[data-kts-h-body]').value = 'TEAM STORE REQUEST\n\n' + sum.lines.join('\n') + '\n\nContact: ' + data('name') + ' / ' + data('phone') + ' / ' + data('email');
var kbA = (window.kbGetAttribution ? window.kbGetAttribution() : {}), kbEid = (window.kbNewEventId ? window.kbNewEventId() : 'kb_' + Date.now());
// primary: the ops app (Team Store tab + GHL contact). The Shopify email below is a non-blocking extra notification.
var primary = fetch(OPS + '/api/team-store-request', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({
team_name: data('team'), sport: data('sport'), player_count: +data('players') || null, needed_by: data('deadline') || null,
colors: colors.map(function (c) { return { name: c.name, hex: c.hex }; }), requested_password: data('password'),
contact_name: data('name'), contact_phone: data('phone'), contact_email: data('email'), notes: data('notes') || null, logo_urls: kbUp,
attribution: kbA, visitor_id: kbA.visitor_id || '', event_id: kbEid }) })
.then(function (r) { return r.json().then(function (j) { return !!(r.ok && j && j.ok); }, function () { return false; }); });
try { fetch(form.action, { method: 'POST', body: new FormData(form), credentials: 'same-origin', redirect: 'follow' }).catch(function () {}); } catch (e) {}
return primary.then(function (ok) {
if (!ok) throw new Error('x');
try { if (window.kbTrackLead) kbTrackLead({ eventId: kbEid, googleSendTo: 'AW-18252221379/siG9COe3qcwcEMOXq_9D', email: data('email'), phone: data('phone') }); } catch (e) {}
done();
});
}).catch(function () { btn.disabled = false; btn.textContent = label; showErr('That did not go through. Please try again, or text or call us at 332-318-2729.'); });
});
})();