NICEY DIY STUDIO

Create Your Bracelet

Design your own bracelet 💗

LIVE PREVIEW

Your Bracelet

Choose your beads Tap a bead below to begin
✦ Tap bead to remove ✦ Hold & drag anywhere ✦ Position stays where you leave it
Pieces 0
Total $0.00
DIY BEADS

Choose Your Beads

0 / 18
(function(){ const root = document.getElementById( 'NiceyDIY-template--16375217815747__nicey_diy_bracelet_RXVYxt' ); if(!root) return; const bracelet = root.querySelector( '[data-bracelet]' ); const empty = root.querySelector( '[data-empty]' ); const countEls = root.querySelectorAll( '[data-count]' ); const priceEl = root.querySelector( '[data-price]' ); const message = root.querySelector( '[data-message]' ); const clearBtn = root.querySelector( '[data-clear]' ); const undoBtn = root.querySelector( '[data-undo]' ); const cartBtn = root.querySelector( '[data-add-cart]' ); const beadButtons = root.querySelectorAll( '[data-bead-button]' ); const maxBeads = Number( 18 ); const basePrice = Number( 0 ); const variantId = null ; let beads = []; let history = []; function money(value){ return '$' + Number(value).toFixed(2); } function showMessage(text){ message.textContent = text; clearTimeout( message._timer ); message._timer = setTimeout( function(){ message.textContent = ''; }, 2200 ); } function saveHistory(){ history.push( beads.map( function(bead){ return { name:bead.name, price:bead.price, image:bead.image, uid:bead.uid, x:bead.x, y:bead.y, manual:bead.manual }; } ) ); if(history.length > 30){ history.shift(); } } function getLayout(){ const rect = bracelet.getBoundingClientRect(); const centerX = rect.width / 2; const centerY = rect.height / 2; const mobile = rect.width < 500; const radiusX = Math.min( rect.width * (mobile ? .35 : .36), mobile ? 118 : 175 ); const radiusY = Math.min( rect.height * (mobile ? .34 : .35), mobile ? 98 : 145 ); return { rect, centerX, centerY, radiusX, radiusY }; } function autoPositionNewBeads(){ const layout = getLayout(); const autoBeads = beads.filter( function(bead){ return !bead.manual; } ); autoBeads.forEach( function(bead,index){ const angle = ( index / Math.max( autoBeads.length, 1 ) ) * Math.PI * 2 - Math.PI / 2; bead.x = layout.centerX + Math.cos(angle) * layout.radiusX; bead.y = layout.centerY + Math.sin(angle) * layout.radiusY; } ); } function renderBracelet(){ bracelet .querySelectorAll( '.bracelet-bead' ) .forEach( function(el){ el.remove(); } ); if(beads.length === 0){ empty.style.display = 'flex'; }else{ empty.style.display = 'none'; } autoPositionNewBeads(); let total = basePrice; beads.forEach( function(bead){ total += Number( bead.price || 0 ); } ); countEls.forEach( function(el){ el.textContent = beads.length; } ); priceEl.textContent = money(total); beads.forEach( function(bead,index){ const el = document.createElement( 'button' ); el.type = 'button'; el.className = 'bracelet-bead'; el.style.left = bead.x + 'px'; el.style.top = bead.y + 'px'; const img = document.createElement( 'img' ); img.src = bead.image; img.alt = bead.name; el.appendChild(img); enableFreeDrag( el, bead, index ); bracelet.appendChild( el ); } ); } function enableFreeDrag( el, bead, index ){ let dragging = false; let moved = false; let startX = 0; let startY = 0; let pointerId = null; function down(e){ if( e.pointerType === 'mouse' && e.button !== 0 ){ return; } dragging = true; moved = false; pointerId = e.pointerId; startX = e.clientX; startY = e.clientY; el.classList.add( 'is-dragging' ); document.addEventListener( 'pointermove', move, { passive:false } ); document.addEventListener( 'pointerup', up ); document.addEventListener( 'pointercancel', cancel ); e.preventDefault(); e.stopPropagation(); } function move(e){ if(!dragging) return; if( e.pointerId !== pointerId ){ return; } const dx = e.clientX - startX; const dy = e.clientY - startY; if( Math.sqrt( dx * dx + dy * dy ) > 5 ){ moved = true; } const rect = bracelet.getBoundingClientRect(); const radius = el.offsetWidth / 2; let x = e.clientX - rect.left; let y = e.clientY - rect.top; x = Math.max( radius, Math.min( rect.width - radius, x ) ); y = Math.max( radius, Math.min( rect.height - radius, y ) ); el.style.left = x + 'px'; el.style.top = y + 'px'; e.preventDefault(); } function up(e){ if(!dragging) return; if( e.pointerId !== pointerId ){ return; } cleanup(); if(!moved){ saveHistory(); beads.splice( index, 1 ); renderBracelet(); return; } const rect = bracelet.getBoundingClientRect(); const radius = el.offsetWidth / 2; let x = e.clientX - rect.left; let y = e.clientY - rect.top; x = Math.max( radius, Math.min( rect.width - radius, x ) ); y = Math.max( radius, Math.min( rect.height - radius, y ) ); saveHistory(); bead.x = x; bead.y = y; bead.manual = true; renderBracelet(); } function cancel(){ if(!dragging) return; cleanup(); renderBracelet(); } function cleanup(){ dragging = false; pointerId = null; el.classList.remove( 'is-dragging' ); document.removeEventListener( 'pointermove', move ); document.removeEventListener( 'pointerup', up ); document.removeEventListener( 'pointercancel', cancel ); } el.addEventListener( 'pointerdown', down ); } beadButtons.forEach( function(button){ button.addEventListener( 'click', function(){ if( beads.length >= maxBeads ){ showMessage( 'Maximum ' + maxBeads + ' beads.' ); return; } if( !button.dataset.image ){ showMessage( 'Please add an image for this bead.' ); return; } saveHistory(); beads.push({ name: button.dataset.name || 'Bead', price: Number( button.dataset.price || 0 ), image: button.dataset.image, uid: Date.now() + '-' + Math.random(), x:0, y:0, manual:false }); renderBracelet(); } ); } ); clearBtn.addEventListener( 'click', function(){ if(!beads.length){ return; } saveHistory(); beads = []; renderBracelet(); } ); undoBtn.addEventListener( 'click', function(){ if(!history.length){ showMessage( 'Nothing to undo.' ); return; } beads = history.pop(); renderBracelet(); } ); cartBtn.addEventListener( 'click', async function(){ if(!beads.length){ showMessage( 'Please choose at least one bead.' ); return; } if(!variantId){ showMessage( 'Please select your bracelet product.' ); return; } const design = beads.map( function(bead,index){ return ( (index + 1) + '. ' + bead.name ); } ).join( ' | ' ); const positionData = beads.map( function(bead,index){ return ( (index + 1) + ':' + Math.round(bead.x) + ',' + Math.round(bead.y) ); } ).join( ' | ' ); cartBtn.disabled = true; cartBtn.textContent = 'Adding...'; try{ const response = await fetch( window.Shopify.routes.root + 'cart/add.js', { method:'POST', headers:{ 'Content-Type': 'application/json' }, body: JSON.stringify({ items:[ { id: Number( variantId ), quantity:1, properties:{ 'DIY Bracelet Design': design, 'Bead Count': String( beads.length ), 'Bead Positions': positionData, 'DIY Display Price': money( basePrice + beads.reduce( function( sum, bead ){ return ( sum + Number( bead.price || 0 ) ); }, 0 ) ) } } ] }) } ); if(!response.ok){ throw new Error( 'Cart error' ); } cartBtn.textContent = 'Added ✓'; showMessage( 'Custom bracelet added to cart.' ); setTimeout( function(){ window.location.href = window.Shopify.routes.root + 'cart'; }, 500 ); }catch(error){ cartBtn.disabled = false; cartBtn.textContent = 'Add Custom Bracelet'; showMessage( 'Could not add to cart.' ); } } ); window.addEventListener( 'resize', function(){ const layout = getLayout(); beads.forEach( function(bead){ if(!bead.manual){ return; } bead.x = Math.max( 30, Math.min( layout.rect.width - 30, bead.x ) ); bead.y = Math.max( 30, Math.min( layout.rect.height - 30, bead.y ) ); } ); renderBracelet(); } ); renderBracelet(); })();