Last active
September 3, 2026 16:08
-
-
Save gingersoulrecords/c99af5cec80eacdc73cf34c317d49b4c to your computer and use it in GitHub Desktop.
Big Sky Cart Prototype
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>Big Sky — cart drawer prototype</title> | |
| <style> | |
| :root{--s0:#F1EFE8;--s1:#F7F6F2;--s2:#fff;--tp:#2C2C2A;--ts:#5F5E5A;--tm:#888780;--bd:rgba(0,0,0,.12);--bds:rgba(0,0,0,.22);--r:8px} | |
| *{box-sizing:border-box} | |
| body{margin:0;padding:2rem 1rem 3rem;background:var(--s0);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:var(--tp);-webkit-font-smoothing:antialiased} | |
| .wrap{max-width:760px;margin:0 auto} | |
| h1{font-size:22px;font-weight:500;margin:0 0 .25rem} | |
| p.lede{font-size:15px;color:var(--ts);line-height:1.6;margin:0 0 1.25rem} | |
| p.sub{font-size:14px;color:var(--ts);line-height:1.6;margin:0 0 1rem} | |
| button{font-family:inherit;background:transparent;border:.5px solid var(--bds);border-radius:var(--r);padding:8px 14px;font-size:14px;color:var(--tp);cursor:pointer} | |
| button:hover{filter:brightness(.97)} | |
| button:active{transform:scale(.98)} | |
| .tabs{display:flex;gap:8px;margin-bottom:1rem} | |
| .tab.on{background:var(--tp);color:#fff;border-color:var(--tp)} | |
| .stage{background:var(--s1);border-radius:12px;padding:1.25rem} | |
| .note{font-size:13px;color:var(--ts);line-height:1.7;margin-top:2rem;padding-top:1.25rem;border-top:.5px solid var(--bd)} | |
| .note strong{font-weight:600} | |
| .hide{display:none} | |
| .track::-webkit-scrollbar{display:none} | |
| @keyframes pulseGlow{0%,100%{box-shadow:0 0 0 0 rgba(255,255,255,0)}50%{box-shadow:0 0 8px 1px rgba(255,255,255,.55)}} | |
| .closeBar{animation:pulseGlow 1.6s ease-in-out infinite} | |
| @keyframes popIn{0%{transform:scale(.6);opacity:0}60%{transform:scale(1.15)}100%{transform:scale(1);opacity:1}} | |
| .pop{animation:popIn .4s ease-out;display:inline-block} | |
| .stepBtn{width:24px;height:24px;padding:0;font-size:14px;line-height:1;flex:none;display:flex;align-items:center;justify-content:center;background:#fff} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <h1>Cart drawer prototype</h1> | |
| <p class="lede">A working sketch of the slide-out cart. Change quantities, add something from Popular picks, and watch what happens as the order crosses $50.</p> | |
| <div class="tabs"> | |
| <button class="tab on" id="tMob">Mobile</button> | |
| <button class="tab" id="tDesk">Desktop</button> | |
| <button id="reset" style="margin-left:auto">Reset cart</button> | |
| </div> | |
| <div id="mobView"> | |
| <p class="sub">On a phone the cart comes up from the bottom as a sheet, so the shop stays visible behind it. It opens when you tap the cart icon, not automatically on every add.</p> | |
| <div class="stage" style="display:flex;justify-content:center"> | |
| <div style="width:340px;background:#F2F0EA;border:.5px solid var(--bd);border-radius:16px;overflow:hidden"> | |
| <div class="hdr" style="background:#fff;padding:14px 16px 0;display:flex;align-items:center;justify-content:space-between"> | |
| <span style="font-size:17px;font-weight:700">Cart</span><span style="font-size:18px;color:var(--ts);line-height:1">×</span> | |
| </div> | |
| <div class="meterWrap" style="background:#fff;padding:16px 16px 16px"> | |
| <div class="mMsg" style="text-align:center;line-height:1.35"></div> | |
| </div> | |
| <div style="height:8px;background:#E7E4DC;overflow:hidden"><div class="mBar" style="height:100%;transition:width .45s cubic-bezier(.2,.8,.2,1),background .5s"></div></div> | |
| <div class="items" style="background:#fff;padding:14px 16px 18px"></div> | |
| <div class="recBlock" style="background:#E8E4DA;padding:20px 0 20px;border-top:.5px solid rgba(0,0,0,.1)"> | |
| <div style="font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#8A857A;padding:0 0 12px 16px">Most popular</div> | |
| <div class="track" style="display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none"></div> | |
| <div style="margin:12px 16px 0;height:3px;border-radius:2px;background:rgba(0,0,0,.12);overflow:hidden"><div class="rail" style="height:100%;background:#4A463D;border-radius:2px;width:40%;transition:width .15s,margin-left .15s"></div></div> | |
| </div> | |
| <div style="padding:16px 14px 14px;background:#F2F0EA"> | |
| <div style="background:#fff;border-radius:12px;padding:16px"> | |
| <div style="font-size:16px;font-weight:700;margin-bottom:12px">Order summary</div> | |
| <div style="display:flex;justify-content:space-between;font-size:14px;margin-bottom:6px"><span style="color:var(--ts)">Subtotal</span><span class="subTot"></span></div> | |
| <div style="display:flex;justify-content:space-between;align-items:center;font-size:14px;padding-bottom:11px;border-bottom:.5px solid var(--bd)"><span style="color:var(--ts)">Shipping</span><span class="shipTot"></span></div> | |
| <div style="display:flex;justify-content:space-between;align-items:baseline;margin-top:11px"><span style="font-size:14px;font-weight:600">Estimated total</span><span class="estTot" style="font-size:16px;font-weight:700"></span></div> | |
| <div style="font-size:12px;color:var(--ts);margin-top:2px">plus tax, calculated at checkout</div> | |
| <button style="width:100%;font-size:14px;font-weight:700;letter-spacing:.08em;padding:14px;margin-top:14px;background:#111;color:#fff;border-color:#111">CHECKOUT</button> | |
| <div style="font-size:11px;color:var(--ts);line-height:1.5;margin-top:10px;text-align:center" text-wrap:balance">Free shipping over $50. <span style="text-decoration:underline">Some remote areas excluded.</span> Sorry, no PO boxes.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="deskView" class="hide"> | |
| <p class="sub">On a larger screen it slides in from the right as a full-height panel. The progress bar and totals stay pinned while the items scroll.</p> | |
| <div class="stage"> | |
| <div style="position:relative;height:520px;border-radius:8px;overflow:hidden;background:#fff;border:.5px solid var(--bd)"> | |
| <div style="position:absolute;inset:0;display:flex;flex-direction:column"> | |
| <div style="padding:8px;background:#111;text-align:center;flex:none"><span style="font-size:12px;color:#fff">Free shipping on orders over $50</span></div> | |
| <div style="padding:14px 20px;border-bottom:.5px solid var(--bd);display:flex;align-items:center;justify-content:space-between;flex:none"><span style="font-size:15px;font-weight:700">BIG SKY</span><span style="font-size:13px;color:var(--ts)">Shop · Brands · About</span></div> | |
| <div style="flex:1;padding:20px;display:grid;grid-template-columns:repeat(3,1fr);gap:14px;align-content:start"> | |
| <div style="height:100px;border-radius:8px;background:var(--s0)"></div><div style="height:100px;border-radius:8px;background:var(--s0)"></div><div style="height:100px;border-radius:8px;background:var(--s0)"></div> | |
| <div style="height:100px;border-radius:8px;background:var(--s0)"></div><div style="height:100px;border-radius:8px;background:var(--s0)"></div><div style="height:100px;border-radius:8px;background:var(--s0)"></div> | |
| </div> | |
| </div> | |
| <div style="position:absolute;inset:0;background:rgba(0,0,0,.3)"></div> | |
| <div style="position:absolute;top:0;right:0;bottom:0;width:360px;background:#F2F0EA;display:flex;flex-direction:column"> | |
| <div class="hdr" style="background:#fff;padding:14px 16px 0;display:flex;align-items:center;justify-content:space-between;flex:none"> | |
| <span style="font-size:17px;font-weight:700">Cart</span><span style="font-size:18px;color:var(--ts);line-height:1">×</span> | |
| </div> | |
| <div class="meterWrap" style="background:#fff;padding:16px 16px 16px;flex:none"> | |
| <div class="mMsg" style="text-align:center;line-height:1.35"></div> | |
| </div> | |
| <div style="height:8px;background:#E7E4DC;overflow:hidden;flex:none"><div class="mBar" style="height:100%;transition:width .45s cubic-bezier(.2,.8,.2,1),background .5s"></div></div> | |
| <div style="flex:1;overflow-y:auto"> | |
| <div class="items" style="background:#fff;padding:14px 16px 18px"></div> | |
| <div class="recBlock" style="background:#E8E4DA;padding:20px 0 20px;border-top:.5px solid rgba(0,0,0,.1)"> | |
| <div style="font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#8A857A;padding:0 0 12px 16px">Most popular</div> | |
| <div class="track" style="display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none"></div> | |
| <div style="margin:12px 16px 0;height:3px;border-radius:2px;background:rgba(0,0,0,.12);overflow:hidden"><div class="rail" style="height:100%;background:#4A463D;border-radius:2px;width:40%;transition:width .15s,margin-left .15s"></div></div> | |
| </div> | |
| </div> | |
| <div style="padding:14px;background:#F2F0EA;flex:none"> | |
| <div style="background:#fff;border-radius:12px;padding:16px"> | |
| <div style="display:flex;justify-content:space-between;font-size:14px;margin-bottom:6px"><span style="color:var(--ts)">Subtotal</span><span class="subTot"></span></div> | |
| <div style="display:flex;justify-content:space-between;align-items:center;font-size:14px;padding-bottom:11px;border-bottom:.5px solid var(--bd)"><span style="color:var(--ts)">Shipping</span><span class="shipTot"></span></div> | |
| <div style="display:flex;justify-content:space-between;align-items:baseline;margin-top:11px"><span style="font-size:14px;font-weight:600">Estimated total</span><span class="estTot" style="font-size:16px;font-weight:700"></span></div> | |
| <div style="font-size:12px;color:var(--ts);margin-top:2px">plus tax, calculated at checkout</div> | |
| <button style="width:100%;font-size:14px;font-weight:700;letter-spacing:.08em;padding:13px;margin-top:12px;background:#111;color:#fff;border-color:#111">CHECKOUT</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <p class="note">A sketch, not the finished thing. Product photos, type and spacing would match the site. Worth reacting to: <strong>the wording of the nudge</strong>, <strong>the struck-through shipping charge when the order clears $50</strong>, and <strong>whether the Most popular row feels useful or pushy</strong>. The cart opens on tapping the cart icon, never automatically. Taxes and the total are deliberately left as estimates so nothing here can be contradicted at checkout.</p> | |
| </div> | |
| <script> | |
| (function(){ | |
| var T=50,S=20,CAP=4,wasFree=false; | |
| var start=[{n:"Cinnamon 6-Pack",p:18,q:1},{n:"Chocolate Mint 6-Pack",p:18,q:1}]; | |
| var cart=JSON.parse(JSON.stringify(start)); | |
| var best=[{n:"Cotton Candy 6-Pack",p:18},{n:"Rocket Pop 6-Pack",p:18},{n:"Blue Raspberry 6-Pack",p:18},{n:"Peppermint 6-Pack",p:18},{n:"Wintergreen 6-Pack",p:18},{n:"Marshmallow 6-Pack",p:18},{n:"Ginger Delights 12-Pack",p:36},{n:"Citrus Delights 12-Pack",p:36}]; | |
| function all(s){return Array.prototype.slice.call(document.querySelectorAll(s))} | |
| function money(){return cart.reduce(function(a,b){return a+b.q*b.p},0)} | |
| function mixSky(t){var n=[11,34,64],d=[46,155,230]; | |
| return "rgb("+Math.round(n[0]+(d[0]-n[0])*t)+","+Math.round(n[1]+(d[1]-n[1])*t)+","+Math.round(n[2]+(d[2]-n[2])*t)+")";} | |
| function avail(){var h=cart.map(function(c){return c.n});return best.filter(function(b){return h.indexOf(b.n)<0}).slice(0,CAP)} | |
| function rails(){ | |
| all(".track").forEach(function(t){ | |
| var r=t.parentNode.querySelector(".rail"); if(!r||!t.scrollWidth) return; | |
| var max=t.scrollWidth-t.clientWidth; | |
| var w=Math.max(18,Math.round(t.clientWidth/t.scrollWidth*100)); | |
| r.style.width=w+"%"; r.style.marginLeft=(max>0?(t.scrollLeft/max)*(100-w):0)+"%"; | |
| }); | |
| } | |
| function draw(){ | |
| var sub=money(), free=sub>=T, gap=Math.max(0,T-sub), pct=Math.min(100,Math.round(sub/T*100)); | |
| all(".items").forEach(function(box){ | |
| box.innerHTML=""; | |
| cart.forEach(function(it,i){ | |
| var off=it.q<=1; | |
| var r=document.createElement("div"); | |
| r.style.cssText="display:flex;align-items:center;gap:12px;padding:12px 0"+(i<cart.length-1?";border-bottom:.5px solid var(--bd)":""); | |
| r.innerHTML='<div style="width:60px;height:45px;border-radius:5px;background:#EDEAE2;flex:none"></div>'+ | |
| '<div style="flex:1;min-width:0"><div style="font-size:13px;font-weight:600;line-height:1.3">Big Sky Mints '+it.n+'</div>'+ | |
| '<div style="display:flex;align-items:center;gap:8px;margin-top:3px"><span style="font-size:13px;color:var(--ts)">$'+(it.q*it.p).toFixed(2)+'</span>'+ | |
| '<button data-rm="'+i+'" style="border:none;background:none;padding:0;font-size:12px;color:var(--ts);text-decoration:underline;cursor:pointer;font-family:inherit">Remove</button></div></div>'+ | |
| '<div style="display:flex;align-items:center;gap:6px;flex:none">'+ | |
| '<button class="stepBtn" '+(off?'disabled style="opacity:.35;cursor:default"':'')+' data-d="-1" data-i="'+i+'" aria-label="Decrease">−</button>'+ | |
| '<span style="font-size:13px;min-width:12px;text-align:center">'+it.q+'</span>'+ | |
| '<button class="stepBtn" data-d="1" data-i="'+i+'" aria-label="Increase">+</button></div>'; | |
| box.appendChild(r); | |
| }); | |
| }); | |
| var raw=Math.min(1,sub/T); | |
| all(".mMsg").forEach(function(m){ | |
| m.innerHTML = free | |
| ? '<div class="'+(wasFree?"":"pop")+'" style="font-size:16px;font-weight:700;color:#1B7FC4">🎉 Free Shipping unlocked!</div>'+ | |
| '<div style="font-size:12px;color:var(--ts);margin-top:3px">$20 saved. Nice one.</div>' | |
| : '<div><span style="font-size:14px;font-weight:500">You’re </span>'+ | |
| '<span style="font-size:17px;font-weight:700;letter-spacing:-.01em">$'+(gap%1===0?gap.toFixed(0):gap.toFixed(2))+'</span>'+ | |
| '<span style="font-size:14px;font-weight:500"> away from </span>'+ | |
| '<span style="font-size:14px;font-weight:700">Free Shipping</span></div>'+ | |
| '<div style="font-size:12px;color:var(--ts);margin-top:3px">(you’ll save $20)</div>'; | |
| }); | |
| all(".mBar").forEach(function(b){ | |
| b.style.width=(free?100:Math.max(9,pct))+"%"; | |
| b.style.background = free ? "#2E9BE6" : mixSky(raw); | |
| }); | |
| wasFree=free; | |
| var list=avail(); | |
| all(".recBlock").forEach(function(blk){ | |
| var t=blk.querySelector(".track"); | |
| if(!list.length){ blk.style.display="none"; return; } | |
| blk.style.display="block"; t.innerHTML=""; | |
| var lead=document.createElement("div"); lead.style.cssText="flex:0 0 6px;width:6px"; t.appendChild(lead); | |
| list.forEach(function(b){ | |
| var c=document.createElement("div"); | |
| c.style.cssText="flex:none;width:278px;scroll-snap-align:center;background:#fff;border-radius:10px;padding:11px;display:flex;align-items:center;gap:11px"; | |
| c.innerHTML='<div style="width:56px;height:42px;border-radius:5px;background:#F2F0EA;flex:none"></div>'+ | |
| '<div style="flex:1;min-width:0"><div style="font-size:13px;font-weight:600;line-height:1.3">'+b.n+'</div>'+ | |
| '<div style="font-size:13px;color:var(--ts);margin-top:2px">$'+b.p.toFixed(2)+'</div></div>'+ | |
| '<button class="addOne" data-n="'+b.n+'" data-p="'+b.p+'" style="font-size:12px;font-weight:700;letter-spacing:.05em;padding:8px 13px;flex:none;background:#F2F0EA;border-color:rgba(0,0,0,.14)">ADD</button>'; | |
| t.appendChild(c); | |
| }); | |
| var tail=document.createElement("div"); tail.style.cssText="flex:0 0 6px;width:6px"; t.appendChild(tail); | |
| t.onscroll=rails; | |
| }); | |
| all(".addOne").forEach(function(b){ | |
| b.onclick=function(){ cart.push({n:b.getAttribute("data-n"),p:+b.getAttribute("data-p"),q:1}); draw(); }; | |
| }); | |
| setTimeout(rails,0); | |
| all(".subTot").forEach(function(e){e.textContent="$"+sub.toFixed(2)}); | |
| all(".shipTot").forEach(function(e){ | |
| e.innerHTML = free ? '<span style="color:var(--ts);text-decoration:line-through;margin-right:6px">$20.00</span><span style="font-weight:700;color:#1B7FC4">FREE</span>' : '$20.00'; | |
| }); | |
| all(".estTot").forEach(function(e){e.textContent="$"+(sub+(free?0:S)).toFixed(2)+" CAD"}); | |
| all(".items button[data-i]").forEach(function(bt){ | |
| bt.onclick=function(){ if(bt.disabled) return; | |
| var i=+bt.getAttribute("data-i"); cart[i].q=Math.max(1,cart[i].q+(+bt.getAttribute("data-d"))); draw(); }; | |
| }); | |
| all(".items button[data-rm]").forEach(function(bt){ | |
| bt.onclick=function(){ cart.splice(+bt.getAttribute("data-rm"),1); | |
| if(!cart.length) cart=[{n:"Cinnamon 6-Pack",p:18,q:1}]; draw(); }; | |
| }); | |
| } | |
| document.getElementById("tMob").onclick=function(){document.getElementById("mobView").classList.remove("hide");document.getElementById("deskView").classList.add("hide");this.classList.add("on");document.getElementById("tDesk").classList.remove("on");setTimeout(rails,0)}; | |
| document.getElementById("tDesk").onclick=function(){document.getElementById("deskView").classList.remove("hide");document.getElementById("mobView").classList.add("hide");this.classList.add("on");document.getElementById("tMob").classList.remove("on");setTimeout(rails,0)}; | |
| document.getElementById("reset").onclick=function(){cart=JSON.parse(JSON.stringify(start));wasFree=false;draw()}; | |
| draw(); | |
| })(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment