questro
Version:
A lightweight, modular gamification library for React with unique visual components. Features combo meters, daily challenges, achievement toasts, and progress rings. Add points, badges, quests, leaderboards, levels/XP, streaks, and notifications with zero
21 lines (20 loc) • 8.15 kB
JavaScript
import {a,b as b$1,c}from'./chunk-3QNKEEDV.mjs';import {c as c$1}from'./chunk-R2GD7YTX.mjs';import {createContext,useState,useMemo,useEffect,useContext,useCallback}from'react';import {jsx,jsxs}from'react/jsx-runtime';var R=[5,10,25,50,100],b=class o{constructor(t){this.events=a();this.config={userId:t.userId,timeWindow:t.timeWindow??5e3,multiplierIncrement:t.multiplierIncrement??.1,maxMultiplier:t.maxMultiplier??5,minComboForMultiplier:t.minComboForMultiplier??3,onComboBreak:t.onComboBreak??(()=>{}),onComboMilestone:t.onComboMilestone??(()=>{})},this.state={userId:t.userId,currentCombo:0,maxCombo:0,multiplier:1,lastActionTime:0,actions:[],isActive:false};}getCurrentCombo(){return this.state.currentCombo}getMaxCombo(){return this.state.maxCombo}getMultiplier(){return this.state.multiplier}isActive(){return this.state.isActive}addAction(t){let e=b$1();this.state.lastActionTime>0&&e-this.state.lastActionTime>this.config.timeWindow&&this.breakCombo(),this.state.currentCombo+=1,this.state.lastActionTime=e,this.state.isActive=true,this.state.currentCombo>this.state.maxCombo&&(this.state.maxCombo=this.state.currentCombo);let r=this.state.multiplier;if(this.state.currentCombo>=this.config.minComboForMultiplier){let i=this.state.currentCombo-this.config.minComboForMultiplier+1;this.state.multiplier=Math.min(1+i*this.config.multiplierIncrement,this.config.maxMultiplier);}else this.state.multiplier=1;let s={id:c(),userId:this.state.userId,action:t,timestamp:e,createdAt:e,updatedAt:e};this.state.actions.push(s),this.state.actions.length>100&&(this.state.actions=this.state.actions.slice(-100)),this.events.emit("comboIncreased",{combo:this.state.currentCombo,multiplier:this.state.multiplier}),r!==this.state.multiplier&&this.events.emit("multiplierChanged",{oldMultiplier:r,newMultiplier:this.state.multiplier});let n=R.find(i=>i===this.state.currentCombo);return n&&(this.events.emit("comboMilestone",{combo:this.state.currentCombo,multiplier:this.state.multiplier,milestone:n}),this.config.onComboMilestone(this.state.currentCombo,this.state.multiplier)),this.setupTimeout(),s}checkTimeout(){return !this.state.isActive||this.state.lastActionTime===0?false:b$1()-this.state.lastActionTime>this.config.timeWindow?(this.breakCombo(),true):false}reset(){this.breakCombo(),this.state.maxCombo=0,this.state.actions=[];}breakCombo(){if(this.state.currentCombo===0)return;let t=this.state.currentCombo,e=this.state.multiplier;this.state.currentCombo=0,this.state.multiplier=1,this.state.isActive=false,this.state.lastActionTime=0,this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=void 0),this.events.emit("comboBroken",{combo:t,multiplier:e}),this.config.onComboBreak(t,e);}setupTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=setTimeout(()=>{this.checkTimeout();},this.config.timeWindow+100);}toJSON(){return {...this.state}}static fromJSON(t,e){let r=new o(t);return r.state=e,e.isActive&&e.lastActionTime>0&&r.setupTimeout(),r}};var M=createContext(null);function B({children:o,config:t,storage:e=new c$1,storageKey:r=`combo:${t.userId}`}){let[s,n]=useState(true),i=useMemo(()=>new b(t),[t.userId]);return useEffect(()=>{let m=true;return (async()=>{try{let c=await e.get(r);c&&m&&Object.assign(i,b.fromJSON(t,c));}catch(c){console.error("Failed to load combo state:",c);}finally{m&&n(false);}})(),()=>{m=false;}},[e,r,t,i]),useEffect(()=>s?void 0:i.events.on("comboIncreased",async()=>{try{await e.set(r,i.toJSON());}catch(u){console.error("Failed to save combo state:",u);}}),[i,e,r,s]),useEffect(()=>{if(s)return;let m=setInterval(()=>{i.checkTimeout();},1e3);return ()=>clearInterval(m)},[i,s]),s?null:jsx(M.Provider,{value:i,children:o})}function S(){let o=useContext(M);if(!o)throw new Error("useComboContext must be used within a ComboProvider");return o}function O(){let o=S(),[t,e]=useState(o.getCurrentCombo()),[r,s]=useState(o.getMaxCombo()),[n,i]=useState(o.getMultiplier()),[m,u]=useState(o.isActive()),[c,C]=useState(0);useEffect(()=>{let p=o.events.on("comboIncreased",({combo:h,multiplier:v})=>{e(h),s(o.getMaxCombo()),i(v),u(true);}),f=o.events.on("comboBroken",()=>{e(0),i(1),u(false),C(0);});return ()=>{p(),f();}},[o]),useEffect(()=>{if(!m){C(0);return}let p=setInterval(()=>{o.checkTimeout();let f=o.toJSON();if(f.lastActionTime>0){let h=Date.now()-f.lastActionTime,v=Math.max(0,5e3-h);C(v);}},100);return ()=>clearInterval(p)},[o,m]);let w=useCallback(p=>o.addAction(p),[o]),k=useCallback(()=>{o.reset();},[o]);return {combo:t,maxCombo:r,multiplier:n,isActive:m,timeRemaining:c,addAction:w,reset:k}}function D({combo:o,multiplier:t,isActive:e,timeRemaining:r,maxTime:s=5e3,showMultiplier:n=true,style:i,className:m}){let u=r/s*100,c=e&&o>0;return jsxs("div",{className:m,style:{display:"inline-flex",flexDirection:"column",alignItems:"center",gap:"8px",padding:"16px",borderRadius:"12px",background:e?"linear-gradient(135deg, #ff6b35 0%, #f7931e 100%)":"#e2e8f0",boxShadow:e?"0 4px 20px rgba(255, 107, 53, 0.4)":"none",transition:"all 0.3s ease",transform:c?"scale(1.05)":"scale(1)",...i},children:[jsx("div",{style:{fontSize:"32px",fontWeight:"bold",color:e?"#fff":"#64748b",lineHeight:1,animation:c?"comboPulse 0.3s ease":void 0},children:o}),jsx("div",{style:{fontSize:"12px",fontWeight:600,color:e?"rgba(255,255,255,0.9)":"#94a3b8",textTransform:"uppercase",letterSpacing:"0.5px"},children:"Combo"}),e&&jsx("div",{style:{width:"100px",height:"4px",background:"rgba(255,255,255,0.3)",borderRadius:"2px",overflow:"hidden"},children:jsx("div",{style:{width:`${u}%`,height:"100%",background:"#fff",transition:"width 0.1s linear"}})}),n&&t>1&&jsxs("div",{style:{fontSize:"14px",fontWeight:700,color:"#fff",background:"rgba(0,0,0,0.2)",padding:"4px 12px",borderRadius:"12px"},children:["\xD7",t.toFixed(1)]})]})}function L({combo:o,maxCombo:t,multiplier:e,children:r,style:s,className:n}){return jsxs("div",{className:n,style:{display:"flex",flexDirection:"column",gap:"8px",padding:"16px",borderRadius:"8px",background:"#f8fafc",border:"1px solid #e2e8f0",...s},children:[jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[jsxs("div",{children:[jsx("div",{style:{fontSize:"24px",fontWeight:"bold",color:"#1e293b"},children:o}),jsx("div",{style:{fontSize:"12px",color:"#64748b"},children:"Current Combo"})]}),jsxs("div",{style:{textAlign:"right"},children:[jsx("div",{style:{fontSize:"24px",fontWeight:"bold",color:"#64748b"},children:t}),jsx("div",{style:{fontSize:"12px",color:"#64748b"},children:"Best"})]})]}),e>1&&jsxs("div",{style:{padding:"8px 12px",background:"linear-gradient(135deg, #ff6b35 0%, #f7931e 100%)",borderRadius:"6px",textAlign:"center",color:"#fff",fontSize:"14px",fontWeight:600},children:["\u{1F525} ",e.toFixed(1),"\xD7 Multiplier Active"]}),r]})}function J({combo:o,multiplier:t,show:e,style:r,className:s}){if(!e)return null;let n=i=>i>=100?"\u{1F31F}":i>=50?"\u{1F4A5}":i>=25?"\u{1F525}":i>=10?"\u26A1":"\u2728";return jsx("div",{className:s,style:{position:"fixed",top:"50%",left:"50%",transform:"translate(-50%, -50%)",padding:"24px 32px",background:"linear-gradient(135deg, #ff6b35 0%, #f7931e 100%)",borderRadius:"16px",boxShadow:"0 20px 60px rgba(255, 107, 53, 0.6)",zIndex:9999,animation:"comboPopup 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275)",...r},children:jsxs("div",{style:{textAlign:"center",color:"#fff"},children:[jsx("div",{style:{fontSize:"48px",marginBottom:"8px"},children:n(o)}),jsxs("div",{style:{fontSize:"36px",fontWeight:"bold",marginBottom:"4px"},children:[o," COMBO!"]}),t>1&&jsxs("div",{style:{fontSize:"20px",fontWeight:600,opacity:.9},children:["\xD7",t.toFixed(1)," Multiplier"]})]})})}var q=`
comboPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.2); }
}
comboPopup {
0% {
transform: translate(-50%, -50%) scale(0);
opacity: 0;
}
50% {
transform: translate(-50%, -50%) scale(1.1);
}
100% {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
}
`;export{b as a,B as b,S as c,O as d,D as e,L as f,J as g,q as h};//# sourceMappingURL=chunk-Z7N4QMCX.mjs.map
//# sourceMappingURL=chunk-Z7N4QMCX.mjs.map