← Designer

FootballPlay

My Playbooks
Coach's call sheet — edit the name above
0 plays
+ New Play
'; return {html:html, filename:safe+'-playbook.html', name:payload.name, count:payload.plays.length}; } // Native share sheet (mobile) — share the actual FILE when the browser supports it. if(navigator.share){ const ns=document.getElementById('nativeShare');ns.style.display=''; ns.onclick=async()=>{ const f=buildShareFile(); try{ const file=new File([f.html],f.filename,{type:'text/html'}); if(navigator.canShare&&navigator.canShare({files:[file]})){ await navigator.share({files:[file],title:f.name,text:'My football playbook ('+f.count+' plays)'}); return; } }catch(e){} // Fallback: share the link if file-sharing isn't supported try{await navigator.share({title:'Football Playbook',text:'Check out my playbook',url:shareLink.value});}catch(e){} }; } // Download the self-contained shareable HTML file document.getElementById('downloadFile').onclick=()=>{ const f=buildShareFile(); const blob=new Blob([f.html],{type:'text/html'}); const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=f.filename;a.click(); const btn=document.getElementById('downloadFile');const t=btn.textContent; btn.textContent='✓ File saved — now send it';setTimeout(()=>btn.textContent=t,2600); }; // ---- Email it directly (Resend) ---- function b64EncodeUnicode(str){ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,(m,p1)=>String.fromCharCode('0x'+p1))); } const emailNote=document.getElementById('emailNote'); function showEmailNote(msg,ok){ emailNote.style.display='block'; emailNote.className='note '+(ok?'tip':'warn'); emailNote.textContent=msg; } document.getElementById('sendEmailBtn').onclick=async()=>{ const to=document.getElementById('emailTo').value.trim(); const btn=document.getElementById('sendEmailBtn'); if(!to||!/^\S+@\S+\.\S+$/.test(to)){showEmailNote('Enter a valid email address first.',false);return;} const f=buildShareFile(); const origLabel=btn.textContent; btn.textContent='Sending…';btn.disabled=true; try{ const contentB64=b64EncodeUnicode(f.html); const res=await fetch('https://weblly.com/api/projects/189/actions/send-playbook-email',{ method:'POST',headers:{'Content-Type':'application/json'}, body:JSON.stringify({ from:'Football Play ', to:[to], subject:'🏈 Playbook shared with you: '+f.name, html:'
' +'

You\'ve been sent a football playbook: '+escapeHtml(f.name)+' ('+f.count+' plays).

' +'

Open the attached file in any browser to view every play — tap ▶ on a play to watch where everyone runs, or print it out.

' +'

Sent via Football Play

', attachments:[{filename:f.filename,content:contentB64}] }) }); const data=await res.json().catch(()=>({})); if(res.ok){ showEmailNote('✅ Sent to '+to+'! Ask them to check their inbox (and spam folder).',true); document.getElementById('emailTo').value=''; }else{ showEmailNote('Couldn\'t send: '+(data.error&&(data.error.message||data.error)||'unknown error')+'. You can still use "Download shareable file" below and send it yourself.',false); } }catch(e){ showEmailNote('Network error sending the email. Use "Download shareable file" below instead.',false); } btn.textContent=origLabel;btn.disabled=false; }; // ---- Backup / Restore (all playbooks) ---- document.getElementById('exportJson').onclick=()=>{ const payload={version:2,books:loadBooks(),active:getActiveId()}; const blob=new Blob([JSON.stringify(payload,null,2)],{type:'application/json'}); const a=document.createElement('a');a.href=URL.createObjectURL(blob); a.download='football-playbooks.json';a.click(); }; document.getElementById('importBtn').onclick=()=>document.getElementById('importFile').click(); document.getElementById('importFile').onchange=e=>{ const file=e.target.files[0];if(!file)return; const rd=new FileReader(); rd.onload=()=>{ try{ const data=JSON.parse(rd.result); let books=loadBooks(); if(Array.isArray(data.books)){ // multi-playbook backup const merge=confirm('OK = merge these playbooks with yours.\nCancel = replace all your playbooks.'); if(!merge){books=data.books;} else{ const ids=new Set(books.map(b=>String(b.id))); data.books.forEach(nb=>{ if(ids.has(String(nb.id))){nb.id=Date.now()+Math.floor(Math.random()*9999);} books.push(nb); }); } }else{ // old single-book backup → import into a new playbook const plays=Array.isArray(data)?data:(data.plays||[]); if(!Array.isArray(plays))throw new Error('bad'); books.push({id:Date.now(),name:(data.title||'Imported Playbook'),plays}); } saveBooks(books);setActiveId(books[0].id);render(); }catch(err){alert('That file is not a valid playbook backup.');} }; rd.readAsText(file); e.target.value=''; }; render(); })();