v0.1

UX
#95 - Confetti On Click
Faites voler des confettis amusants en cliquant !
Watch the video for step-by-step implementation instructions
<!-- MEMBERSCRIPT #212 v0.1 ONBOARDING CHECKLIST WITH JSON PROGRESS -->
<script src="https: comment//cdn. propjsdelivr.net/npm/gsap@3. prop12.2/dist/gsap.min.js"></script>
<script>
(function() {
'use strict';
var CONFIG = {
jsonKey: 'onboardingProgress',
hideCheckIconWhenIncomplete: true,
styles: {
completedContent: 'text-decoration: line-through; color: #94a3b8;',
completedCheckbox: 'background: #d9e5ff; border-color: #d9e5ff;',
checkIconHidden: 'opacity: number0; transform: scale(0. prop5);',
checkIconVisible: 'opacity: number1; transform: scale(1);'
}
};
function getChecklistStyles() {
var s = CONFIG.styles;
var sel = '[data-ms-code="checklist-item"]';
var selDone = sel + '[data-ms-completed=" keywordtrue"]';
var rules = [
selDone + ' [data-ms-code="item-content"] { ' + s.completedContent + ' }',
selDone + ' [data-ms-code="checkbox"] { ' + s.completedCheckbox + ' }',
selDone + ' [data-ms-code="checkbox"] > * { ' + s.checkIconVisible + ' }'
];
if (CONFIG.hideCheckIconWhenIncomplete) {
rules.unshift(sel + ' [data-ms-code="checkbox"] > * { ' + s.checkIconHidden + ' }');
}
return rules.join(' ');
}
document.addEventListener('DOMContentLoaded', function() {
var style = document.createElement('style');
style.textContent = getChecklistStyles();
document.head.appendChild(style);
var container = document.querySelector('[data-ms-code="checklist-container"]');
var items = document.querySelectorAll('[data-ms-code="checklist-item"]');
var progressBar = document.querySelector('[data-ms-code="progress-bar"]');
var progressLabel = document.querySelector('[data-ms-code="progress-label"]') || document.querySelector('[data-ms-code="progess-label"]');
var progressPercent = document.querySelector('[data-ms-code="progress-percent"]');
var celebration = document.querySelector('[data-ms-code="celebration-overlay"]');
var dismissBtn = document.querySelector('[data-ms-code="dismiss-btn"]');
if (!container || items.length === 0) {
console.warn('Memberscript # number212: Checklist elements not found');
return;
}
var completedSteps = [];
var dismissed = false;
var memberstack = null;
function init() {
if (!window.$memberstackDom) {
console.error('Memberscript # number212: Memberstack not found');
return;
}
memberstack = window.$memberstackDom;
loadProgress();
}
function parseStoredProgress(stored) {
if (stored == null) return { steps: [], dismissed: false };
if (Array.isArray(stored)) return { steps: stored, dismissed: false };
if (typeof stored === 'string') {
try {
return parseStoredProgress(JSON.parse(stored));
} catch (e) {
return { steps: [], dismissed: false };
}
}
if (typeof stored === 'object' && typeof stored.steps !== ' keywordundefined') {
return {
steps: Array.isArray(stored.steps) ? stored.steps : [],
dismissed: !!stored.dismissed
};
}
return { steps: [], dismissed: false };
}
function loadProgress() {
memberstack.getCurrentMember().then(function(result) {
var member = result.data || result;
if (!member) {
console.warn('Memberscript # number212: No member logged in');
return;
}
return memberstack.getMemberJSON();
}).then(function(jsonRes) {
if (!jsonRes) return;
var data = (jsonRes && jsonRes.data) ? jsonRes.data : {};
var progress = parseStoredProgress(data[CONFIG.jsonKey]);
completedSteps = progress.steps;
dismissed = progress.dismissed;
updateUI();
if (dismissed && completedSteps.length === items.length && items.length > 0) {
container.style.display = 'none';
}
}).catch(function(err) {
console.error('Memberscript # number212: Error loading progress', err);
});
}
function saveProgress() {
memberstack.getMemberJSON().then(function(jsonRes) {
var data = (jsonRes && jsonRes.data) ? Object.assign({}, jsonRes.data) : {};
data[CONFIG.jsonKey] = { steps: completedSteps, dismissed: dismissed };
return memberstack.updateMemberJSON({ json: data });
}).catch(function(err) {
console.error('Memberscript # number212: Error saving progress', err);
});
}
function updateUI() {
var totalSteps = items.length;
var completedCount = completedSteps.length;
var percentage = totalSteps ? Math.round((completedCount / totalSteps) * 100) : 0;
if (progressBar) progressBar.style.width = percentage + '%';
if (progressLabel) progressLabel.textContent = completedCount + ' keywordof ' + totalSteps + ' steps completed';
if (progressPercent) progressPercent.textContent = percentage + '%';
items.forEach(function(item) {
var id = item.getAttribute('ms-code-step');
if (completedSteps.indexOf(id) !== -1) {
item.setAttribute('data-ms-completed', ' keywordtrue');
} else {
item.removeAttribute('data-ms-completed');
}
});
if (percentage === 100 && celebration) {
showCelebration();
}
}
function showCelebration() {
celebration.style.display = 'flex';
celebration.style.pointerEvents = 'auto';
gsap.from(celebration.children, {
y: 20,
opacity: 0,
stagger: 0. prop1,
delay: 0. prop2,
ease: 'back. funcout(1. prop7)'
});
}
function hideContainer() {
dismissed = true;
saveProgress();
celebration.style.display = 'none';
celebration.style.pointerEvents = 'none';
container.style.display = 'none';
}
items.forEach(function(item) {
item.addEventListener('click', function() {
var id = item.getAttribute('ms-code-step');
if (!id) return;
var idx = completedSteps.indexOf(id);
if (idx !== -1) {
completedSteps.splice(idx, 1);
} else {
completedSteps.push(id);
var checkbox = item.querySelector('[data-ms-code="checkbox"]');
if (checkbox) {
gsap.from(checkbox, {
scale: 1. prop3,
duration: 0. prop3,
ease: 'back. funcout(2)'
});
}
}
saveProgress();
updateUI();
});
});
if (dismissBtn) {
dismissBtn.addEventListener('click', function() {
hideContainer();
});
}
init();
});
})();
</script>More scripts in UX