Spaces:
Sleeping
Sleeping
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| DistractIQ ยท script.js | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| // โโ Interactive Assets โโ | |
| const sounds = { | |
| pop: new Audio('https://assets.mixkit.co/sfx/preview/mixkit-modern-technology-select-3124.mp3'), | |
| scan: new Audio('https://assets.mixkit.co/sfx/preview/mixkit-futuristic-robotic-data-601.mp3'), | |
| levelUp: new Audio('https://assets.mixkit.co/sfx/preview/mixkit-arcade-retro-changing-tab-206.mp3') | |
| }; | |
| Object.values(sounds).forEach(s => s.volume = 0.2); | |
| const trapRoasts = [ | |
| "Isliye tumhare exams clear nahi hote, distraction ki magnet ho tum! ๐งฒ", | |
| "Focus focus focus... oh look, a useless button! - You, probably. ๐คก", | |
| "Self-control: 0. Button clicking skills: 100. Proud of you. ๐", | |
| "Beta, career par dhyan de lo, is button par nahi. ๐งฌ", | |
| "Physics wallah se pehle distraction wallah banoge tum. ๐" | |
| ]; | |
| /* โโ State โโ */ | |
| const S = { | |
| name: '', quizDone: false, quizAnswers: [], | |
| results: null, history: [], streak: 0, | |
| xp: 0, darkMode: true, | |
| inputs: { study:4, phone:3, social:2, sleep:7, notifications:50 } | |
| }; | |
| /* โโ Persistence โโ */ | |
| function save(){ try{ localStorage.setItem('diq', JSON.stringify(S)); }catch(e){} } | |
| function load(){ | |
| try{ | |
| const d = JSON.parse(localStorage.getItem('diq')||'null'); | |
| if(d){ Object.assign(S, d); } | |
| }catch(e){} | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| GALAXY CANVAS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| (function initGalaxy(){ | |
| const cv = document.getElementById('galaxy'); | |
| const ctx = cv.getContext('2d'); | |
| let W, H, stars=[], nebulas=[]; | |
| function resize(){ W=cv.width=innerWidth; H=cv.height=innerHeight; } | |
| function mkStars(){ | |
| stars = Array.from({length:220},()=>({ | |
| x:Math.random()*W, y:Math.random()*H, | |
| r:Math.random()*1.6+.3, | |
| a:Math.random(), da:(Math.random()-.5)*.008, | |
| s:Math.random()*.4+.1 | |
| })); | |
| nebulas = Array.from({length:5},()=>({ | |
| x:Math.random()*W, y:Math.random()*H, | |
| r:Math.random()*180+80, | |
| h:Math.random()*360, a:Math.random()*.18+.04 | |
| })); | |
| } | |
| function draw(){ | |
| ctx.clearRect(0,0,W,H); | |
| nebulas.forEach(n=>{ | |
| const g=ctx.createRadialGradient(n.x,n.y,0,n.x,n.y,n.r); | |
| g.addColorStop(0,`hsla(${n.h},80%,55%,${n.a})`); | |
| g.addColorStop(1,'transparent'); | |
| ctx.fillStyle=g; ctx.fillRect(0,0,W,H); | |
| }); | |
| stars.forEach(st=>{ | |
| st.a+=st.da; | |
| if(st.a<0||st.a>1) st.da*=-1; | |
| st.x-=st.s*.15; | |
| if(st.x<0) st.x=W; | |
| ctx.beginPath(); | |
| ctx.arc(st.x,st.y,st.r,0,Math.PI*2); | |
| ctx.fillStyle=`rgba(255,255,255,${st.a})`; | |
| ctx.fill(); | |
| }); | |
| requestAnimationFrame(draw); | |
| } | |
| window.addEventListener('resize',()=>{ resize(); mkStars(); }); | |
| resize(); mkStars(); draw(); | |
| })(); | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| SCREEN SWITCHER | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function showScreen(id){ | |
| document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active')); | |
| const el = document.getElementById(id); | |
| el.classList.add('active'); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| LOGIN | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function doLogin(){ | |
| const n = document.getElementById('name-in').value.trim(); | |
| if(!n){ showToast('Please enter your name! ๐'); return; } | |
| S.name = n; | |
| if(!S.quizDone){ showScreen('s-quiz'); initQuiz(); } | |
| else{ showScreen('s-input'); initInputs(); } | |
| save(); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| PERSONALITY QUIZ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| const QUIZ = [ | |
| { q:'When do you feel most productive?', e:'๐', | |
| opts:['Early morning (5โ9 AM)','Late morning (9โ12)','Afternoon vibes','Night owl mode ๐ฆ'] }, | |
| { q:'How often do you check your phone while studying?', e:'๐ฑ', | |
| opts:['Every 5 mins (bad, I know)','Every 30 mins','Only on breaks','I forget phones exist'] }, | |
| { q:'What kills your focus the most?', e:'๐', | |
| opts:['Social media notifications','Background noise','Random thoughts','Hunger / boredom'] }, | |
| { q:'How many hours of deep work can you do daily?', e:'๐ฅ', | |
| opts:['Less than 1 hour','1โ2 hours','3โ4 hours','5+ hours (beast mode)'] } | |
| ]; | |
| let qIdx=0; | |
| function initQuiz(){ | |
| qIdx=0; S.quizAnswers=[]; | |
| renderQ(); | |
| } | |
| function renderQ(){ | |
| const q=QUIZ[qIdx]; | |
| document.getElementById('qemoji').textContent=q.e; | |
| document.getElementById('qtext').textContent=q.q; | |
| document.getElementById('qlabel').textContent=`Question ${qIdx+1} of ${QUIZ.length}`; | |
| document.getElementById('qprog').style.width=`${((qIdx)/QUIZ.length)*100}%`; | |
| const oc=document.getElementById('qopts'); | |
| oc.innerHTML=''; | |
| q.opts.forEach((o,i)=>{ | |
| const b=document.createElement('button'); | |
| b.className='qopt'; b.textContent=o; | |
| b.onclick=()=>pickQ(i, b); | |
| oc.appendChild(b); | |
| }); | |
| // Animate card in | |
| const card=document.getElementById('qcard'); | |
| card.style.animation='none'; | |
| card.offsetHeight; | |
| card.style.animation='popIn .4s cubic-bezier(.34,1.56,.64,1)'; | |
| } | |
| function pickQ(i, btn){ | |
| document.querySelectorAll('.qopt').forEach(b=>b.classList.remove('sel')); | |
| btn.classList.add('sel'); | |
| S.quizAnswers.push(i); | |
| setTimeout(()=>{ | |
| qIdx++; | |
| if(qIdx<QUIZ.length){ renderQ(); } | |
| else{ | |
| S.quizDone=true; save(); | |
| showScreen('s-input'); initInputs(); | |
| } | |
| },420); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| INPUT SLIDERS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| const INPUTS_CFG = [ | |
| { key:'study', icon:'๐', title:'Study Hours Today', desc:'How many hours did you actually study?', min:0, max:16, step:.5, unit:'hrs', def:4 }, | |
| { key:'phone', icon:'๐ฑ', title:'Phone Usage', desc:'Total time on phone today (hours)', min:0, max:16, step:.5, unit:'hrs', def:3 }, | |
| { key:'social', icon:'๐', title:'Social Media Time', desc:'Time spent on Instagram, YouTube, etc.', min:0, max:16, step:.5, unit:'hrs', def:2 }, | |
| { key:'sleep', icon:'๐ด', title:'Sleep Last Night', desc:'How many hours did you sleep?', min:0, max:12, step:.5, unit:'hrs', def:7 }, | |
| { key:'notifications', icon:'๐', title:'Notifications Today', desc:'How many notifications did you receive?', min:0, max:300, step:5, unit:'notifs',def:50 } | |
| ]; | |
| let inpIdx=0; | |
| function initInputs(){ | |
| inpIdx=0; | |
| renderInp(); | |
| renderDots(); | |
| } | |
| function renderInp(){ | |
| const c=INPUTS_CFG[inpIdx]; | |
| document.getElementById('inp-icon').textContent=c.icon; | |
| document.getElementById('inp-title').textContent=c.title; | |
| document.getElementById('inp-desc').textContent=c.desc; | |
| const sl=document.getElementById('inp-slider'); | |
| sl.min=c.min; sl.max=c.max; sl.step=c.step; | |
| sl.value=S.inputs[c.key]!==undefined ? S.inputs[c.key] : c.def; | |
| document.getElementById('slid-unit').textContent=c.unit; | |
| onSlide(sl.value); | |
| // re-trigger animation | |
| const card=document.getElementById('inp-card'); | |
| card.style.animation='none'; card.offsetHeight; | |
| card.style.animation='popIn .4s cubic-bezier(.34,1.56,.64,1)'; | |
| } | |
| function onSlide(v){ | |
| document.getElementById('slid-val').textContent=v; | |
| } | |
| function nextInp(){ | |
| const val=parseFloat(document.getElementById('inp-slider').value); | |
| S.inputs[INPUTS_CFG[inpIdx].key]=val; | |
| // Animate card out | |
| const card=document.getElementById('inp-card'); | |
| card.style.transform='scale(.9) translateY(-30px)'; | |
| card.style.opacity='0'; | |
| setTimeout(()=>{ | |
| card.style.transform=''; card.style.opacity=''; | |
| inpIdx++; | |
| if(inpIdx<INPUTS_CFG.length){ renderInp(); renderDots(); } | |
| else{ save(); callAPI(); } | |
| },350); | |
| } | |
| function renderDots(){ | |
| const dc=document.getElementById('inp-dots'); | |
| dc.innerHTML=''; | |
| INPUTS_CFG.forEach((_,i)=>{ | |
| const d=document.createElement('div'); | |
| d.className='dot'+(i===inpIdx?' active':i<inpIdx?' done':''); | |
| dc.appendChild(d); | |
| }); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| API CALL | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function callAPI() { | |
| // ๐ Scanning sound start | |
| sounds.scan.loop = true; | |
| sounds.scan.play(); | |
| showToast('๐ง Analyzing your focus patternsโฆ'); | |
| const body = { | |
| study_hours_per_day: S.inputs.study, | |
| phone_usage_hours: S.inputs.phone, | |
| social_media_hours: S.inputs.social, | |
| sleep_hours: S.inputs.sleep, | |
| notifications: S.inputs.notifications | |
| }; | |
| fetch('/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) | |
| .then(r => r.json()) | |
| .then(d => { | |
| // ๐ Scanning sound stop | |
| sounds.scan.pause(); | |
| sounds.scan.currentTime = 0; | |
| if (d.error) { showToast('โ ๏ธ ' + d.error); return; } | |
| S.results = d; | |
| processResults(d); | |
| showScreen('s-dash'); | |
| showTab('home'); | |
| updateStreak(); | |
| save(); | |
| // ๐ Level Up sound if good performance | |
| if (d.productivity > 80) { | |
| sounds.levelUp.play(); | |
| } | |
| setTimeout(() => scheduleNotif(d.score), 4000); | |
| }) | |
| .catch(e => { | |
| // ๐ Error aane par bhi sound stop karein | |
| sounds.scan.pause(); | |
| showToast('Connection error. Please try again.'); | |
| console.error(e); | |
| }); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| PROCESS & RENDER RESULTS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function processResults(d){ | |
| const {score, risk, productivity, is_focused} = d; | |
| // XP | |
| const gainedXP = Math.round(productivity * 5); | |
| S.xp = (S.xp||0) + gainedXP; | |
| saveHistory(d); | |
| // Greeting | |
| const hour=new Date().getHours(); | |
| const greet=hour<12?'Good Morning โ๏ธ':hour<17?'Good Afternoon ๐ค':hour<20?'Good Evening ๐':'Good Night ๐'; | |
| document.getElementById('greeting').textContent=`${greet}, ${S.name}! ๐`; | |
| // Sarcasm | |
| document.getElementById('sarcasm').textContent=getSarcasm(score, hour); | |
| document.getElementById('sarcasm').style.borderColor=score>75?'rgba(239,68,68,.4)':score>45?'rgba(245,158,11,.4)':'rgba(16,185,129,.4)'; | |
| // Animate rings | |
| animRing('rg-dist', score, score>75?'#ef4444':score>45?'#f59e0b':'#10b981'); | |
| animRing('rg-risk', risk, risk>75?'#ef4444':risk>45?'#f59e0b':'#10b981'); | |
| animRing('rg-prod', productivity, productivity<40?'#ef4444':productivity<70?'#f59e0b':'#10b981'); | |
| animNum('n-dist', score); | |
| animNum('n-risk', risk); | |
| animNum('n-prod', productivity); | |
| // Persona | |
| const persona=getPersona(score, productivity, d.inputs||S.inputs); | |
| document.getElementById('p-icon').textContent=persona.icon; | |
| document.getElementById('p-name').textContent=persona.name; | |
| document.getElementById('p-desc').textContent=persona.desc; | |
| // Level & XP | |
| const lv=getLevel(S.xp); | |
| document.getElementById('lvl-name').textContent=lv.name; | |
| document.getElementById('lvl-fill').style.width=lv.pct+'%'; | |
| document.getElementById('xp-ct').textContent=S.xp; | |
| document.getElementById('xp-ct2').textContent=S.xp; | |
| document.getElementById('xp-max').textContent=lv.max; | |
| // Drivers | |
| renderDrivers(d.inputs||S.inputs, score); | |
| // Optimizer | |
| renderOptimizer(d.inputs||S.inputs, score, productivity); | |
| // Quote | |
| document.getElementById('quote-txt').textContent=getQuote(); | |
| // Profile | |
| document.getElementById('prof-name').textContent=S.name; | |
| document.getElementById('prof-persona').textContent=persona.name; | |
| // Stats | |
| renderStats(score, productivity, risk); | |
| // Streak | |
| document.getElementById('streak-ct').textContent=S.streak; | |
| document.getElementById('s-big').textContent=S.streak; | |
| // History & breakdown | |
| renderHistory(); | |
| renderBreakdown(d.inputs||S.inputs, score); | |
| // Streaks calendar | |
| renderCal(); | |
| // Achievements | |
| renderAch(); | |
| } | |
| /* โโ Ring animation โโ */ | |
| function animRing(id, val, color){ | |
| const el=document.getElementById(id); | |
| el.style.stroke=color; | |
| const offset=264-(264*(val/100)); | |
| requestAnimationFrame(()=>{ el.style.strokeDashoffset=offset; }); | |
| } | |
| function animNum(id, target){ | |
| const el=document.getElementById(id); | |
| let cur=0; const dur=1200; const start=performance.now(); | |
| function step(now){ | |
| const p=Math.min((now-start)/dur,1); | |
| el.textContent=Math.round(cur+(target-cur)*easeOut(p)); | |
| if(p<1) requestAnimationFrame(step); | |
| } | |
| requestAnimationFrame(step); | |
| } | |
| function easeOut(t){ return 1-Math.pow(1-t,3); } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| CONTENT GENERATORS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function getSarcasm(score, hour){ | |
| if(hour>=23||hour<5){ | |
| const lateArr=['Sleep is optional, regret is guaranteed. ๐ญ','Why are you awake? Your productivity isn\'t. ๐','Your brain needs rest, not a late-night doom scroll.','2 AM productivity? Bold strategy. Let us know how it goes.']; | |
| return rnd(lateArr); | |
| } | |
| if(score>75){ | |
| return rnd(['Focus gaya tel lene ๐ญ','Productivity just left the chat.','Phone se rishta thoda kam karo. ๐ฑ','Your phone has more screen time than your textbook.','Distraction level: Olympic gold medalist.','Your attention span just filed for bankruptcy.']); | |
| } | |
| if(score>45){ | |
| return rnd(['You\'re almost productive. Almost. ๐ค','Some focus detectedโฆ very little.','Mediocre effort detected. Could be worse. Could be better.','The Wi-Fi is testing you and you\'re losing.','Half-focus is like half a parachute. ๐ช']); | |
| } | |
| return rnd(['This is suspiciously impressive. ๐','Look at you getting things done! ๐','Productivity unlocked. Who are you?','Your focus game is on another level today.','Deep work mode: ACTIVATED. We stan. ๐ฅ']); | |
| } | |
| function getPersona(score, prod, inp){ | |
| const ph=inp.phone||S.inputs.phone; | |
| const notif=inp.notifications||S.inputs.notifications; | |
| if(prod>78) return {icon:'๐ฅท',name:'Deep Work Ninja',desc:'You enter flow states effortlessly. Elite.'}; | |
| if(ph>7) return {icon:'๐ฑ',name:'Digital Drifter',desc:'Glued to the screen like it owes you money.'}; | |
| if(notif>140)return {icon:'โก',name:'Chronic Multitasker',desc:'You juggle 10 things and finish 2. Progress.'}; | |
| return {icon:'โ๏ธ',name:'Balanced Performer',desc:'Solid effort. A few tweaks and you\'re elite.'}; | |
| } | |
| function getLevel(xp){ | |
| if(xp<500) return {name:'Beginner', pct:Math.round((xp/500)*100), max:500}; | |
| if(xp<2000) return {name:'Builder', pct:Math.round(((xp-500)/1500)*100), max:2000}; | |
| return {name:'Master', pct:Math.round(Math.min(((xp-2000)/3000)*100,100)), max:5000}; | |
| } | |
| function renderDrivers(inp, score){ | |
| const cont=document.getElementById('drivers'); | |
| const drivers=[]; | |
| const ph=inp.phone||S.inputs.phone; | |
| const sm=inp.social||S.inputs.social; | |
| const sl=inp.sleep||S.inputs.sleep; | |
| const nt=inp.notifications||S.inputs.notifications; | |
| const st=inp.study||S.inputs.study; | |
| if(ph>5) drivers.push({icon:'๐ฑ',label:'High Phone Usage', pct:Math.min(100,Math.round(ph/16*100)), color:'#ef4444'}); | |
| if(sm>3) drivers.push({icon:'๐ธ',label:'Social Media', pct:Math.min(100,Math.round(sm/16*100)), color:'#ec4899'}); | |
| if(sl<6) drivers.push({icon:'๐ด',label:'Sleep Deficit', pct:Math.min(100,Math.round((6-sl)/6*100)), color:'#f59e0b'}); | |
| if(nt>80) drivers.push({icon:'๐',label:'Notification Storm',pct:Math.min(100,Math.round(nt/200*100)), color:'#8b5cf6'}); | |
| if(st<3) drivers.push({icon:'๐',label:'Low Study Time', pct:Math.min(100,Math.round((3-st)/3*100)), color:'#06b6d4'}); | |
| if(!drivers.length) drivers.push({icon:'โ ',label:'No major distractions!',pct:5,color:'#10b981'}); | |
| cont.innerHTML=drivers.map(d=>` | |
| <div class="drv"> | |
| <div class="drv-lft">${d.icon} ${d.label}</div> | |
| <div class="drv-bw"><div class="drv-bf" style="width:0%;background:${d.color}" data-w="${d.pct}"></div></div> | |
| <div class="drv-pct">${d.pct}%</div> | |
| </div>`).join(''); | |
| // Animate bars | |
| setTimeout(()=>{ | |
| cont.querySelectorAll('.drv-bf').forEach(b=>{ b.style.width=b.dataset.w+'%'; }); | |
| },200); | |
| } | |
| function renderOptimizer(inp, score, prod){ | |
| const cont=document.getElementById('optimizer'); | |
| const tips=[]; | |
| const sm=inp.social||S.inputs.social; | |
| const ph=inp.phone||S.inputs.phone; | |
| const sl=inp.sleep||S.inputs.sleep; | |
| const nt=inp.notifications||S.inputs.notifications; | |
| const st=inp.study||S.inputs.study; | |
| if(sm>1) tips.push(`๐ Cut social media by 1hr โ +${Math.round(sm*4)}% productivity boost`); | |
| if(ph>3) tips.push(`๐ต Phone-free study blocks โ reduces distraction score by ~${Math.round(ph*3)} pts`); | |
| if(sl<7) tips.push(`๐ Sleep 1hr more โ clears mental fog, +${Math.round((7-sl)*8)}% focus`); | |
| if(nt>50)tips.push(`๐ Silence notifications during study โ recover ${Math.round(nt*.5)} min of deep work`); | |
| if(st<5) tips.push(`๐ Add 1hr of study โ +${Math.round(1*2*5)} productivity XP gained`); | |
| if(!tips.length) tips.push('๐ You\'re optimized! Keep this up for streak bonuses.'); | |
| cont.innerHTML=tips.map(t=>`<div class="tip"><span class="tip-ic">๐ก</span><span>${t}</span></div>`).join(''); | |
| } | |
| const QUOTES=[ | |
| '"Deep work is the superpower of the 21st century." โ Cal Newport', | |
| '"Focus is a matter of deciding what things you\'re NOT going to do." โ John Carmack', | |
| '"Energy, not time, is the fundamental currency of high performance."', | |
| '"The successful warrior is the average person with laser-like focus." โ Bruce Lee', | |
| '"Concentrate all your thoughts upon the work at hand." โ Alexander Graham Bell', | |
| '"Where focus goes, energy flows." โ Tony Robbins', | |
| '"Do one thing at a time, and do it well."', | |
| '"Your future is created by what you do today, not tomorrow."' | |
| ]; | |
| function getQuote(){ return rnd(QUOTES); } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| HISTORY | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function saveHistory(d){ | |
| const entry={ | |
| date: new Date().toLocaleDateString('en-IN',{day:'numeric',month:'short'}), | |
| score: d.score, risk: d.risk, productivity: d.productivity, | |
| persona: getPersona(d.score, d.productivity, d.inputs||S.inputs).name | |
| }; | |
| S.history = [entry, ...(S.history||[])].slice(0,30); | |
| } | |
| function renderHistory(){ | |
| const cont=document.getElementById('hist-list'); | |
| if(!S.history||!S.history.length){ | |
| cont.innerHTML='<div class="muted" style="font-size:.85rem;padding:8px 0">No history yet. Run your first analysis!</div>'; | |
| return; | |
| } | |
| cont.innerHTML=S.history.slice(0,10).map(h=>{ | |
| const cls=h.score>75?'hi':h.score>45?'md':'lo'; | |
| return `<div class="hitem"> | |
| <div class="hdot ${cls}"></div> | |
| <div class="hinfo"> | |
| <div class="hdate">${h.date}</div> | |
| <div class="hscore">Score: ${h.score} ยท Risk: ${h.risk}%</div> | |
| <div class="hpers">${h.persona}</div> | |
| </div> | |
| <div style="font-family:var(--fd);font-size:.9rem;color:${h.productivity>70?'#10b981':h.productivity>45?'#f59e0b':'#ef4444'}">${h.productivity}%</div> | |
| </div>`; | |
| }).join(''); | |
| } | |
| function renderBreakdown(inp, score){ | |
| const cont=document.getElementById('breakdown'); | |
| const ph=inp.phone||S.inputs.phone; | |
| const sm=inp.social||S.inputs.social; | |
| const nt=inp.notifications||S.inputs.notifications; | |
| const st=inp.study||S.inputs.study; | |
| const sl=inp.sleep||S.inputs.sleep; | |
| const bars=[ | |
| {label:'Phone', val:Math.min(100,Math.round(ph/16*100)), color:'#ef4444'}, | |
| {label:'Social', val:Math.min(100,Math.round(sm/16*100)), color:'#ec4899'}, | |
| {label:'Notifs', val:Math.min(100,Math.round(nt/200*100)), color:'#8b5cf6'}, | |
| {label:'Study', val:Math.min(100,Math.round(st/16*100)), color:'#10b981'}, | |
| {label:'Sleep', val:Math.min(100,Math.round(sl/12*100)), color:'#3b82f6'} | |
| ]; | |
| cont.innerHTML=bars.map(b=>` | |
| <div class="bki"> | |
| <div class="bkh"><span>${b.label}</span><span>${b.val}%</span></div> | |
| <div class="bkbg"><div class="bkf" style="width:0%;background:${b.color};color:${b.color}" data-w="${b.val}"></div></div> | |
| </div>`).join(''); | |
| setTimeout(()=>{ | |
| cont.querySelectorAll('.bkf').forEach(b=>{ b.style.width=b.dataset.w+'%'; }); | |
| },200); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| STREAKS & CALENDAR | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function updateStreak(){ | |
| const today=new Date().toDateString(); | |
| const last=S.lastDay||''; | |
| if(last===today) return; | |
| const yesterday=new Date(Date.now()-86400000).toDateString(); | |
| if(last===yesterday){ S.streak=(S.streak||0)+1; } | |
| else{ S.streak=1; } | |
| S.lastDay=today; | |
| S.streakDays=S.streakDays||[]; | |
| S.streakDays.push(today); | |
| save(); | |
| } | |
| function renderCal(){ | |
| const cont=document.getElementById('s-cal'); | |
| const today=new Date(); | |
| const year=today.getFullYear(); | |
| const month=today.getMonth(); | |
| const daysInMonth=new Date(year,month+1,0).getDate(); | |
| const firstDay=new Date(year,month,1).getDay(); | |
| const done=new Set(S.streakDays||[]); | |
| let html=''; | |
| for(let i=0;i<firstDay;i++) html+=`<div class="cday"></div>`; | |
| for(let d=1;d<=daysInMonth;d++){ | |
| const dt=new Date(year,month,d).toDateString(); | |
| const isToday=d===today.getDate(); | |
| const isDone=done.has(dt); | |
| html+=`<div class="cday${isDone?' done':''}${isToday?' today':''}">${d}</div>`; | |
| } | |
| cont.innerHTML=html; | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ACHIEVEMENTS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| const ACHS=[ | |
| {icon:'๐',name:'First Launch', desc:'Completed first analysis', check:()=>S.history&&S.history.length>=1}, | |
| {icon:'๐ฅ',name:'3-Day Streak', desc:'3 days in a row', check:()=>(S.streak||0)>=3}, | |
| {icon:'๐',name:'Focus Diamond', desc:'Productivity > 80%', check:()=>S.results&&S.results.productivity>80}, | |
| {icon:'๐ง',name:'Zen Mode', desc:'Distraction score < 20', check:()=>S.results&&S.results.score<20}, | |
| {icon:'โก',name:'500 XP Club', desc:'Earned 500 XP', check:()=>(S.xp||0)>=500}, | |
| {icon:'๐',name:'Week Warrior', desc:'7-day streak', check:()=>(S.streak||0)>=7}, | |
| ]; | |
| function renderAch(){ | |
| document.getElementById('ach-list').innerHTML=ACHS.map(a=>{ | |
| const on=a.check(); | |
| return `<div class="ach ${on?'on':'off'}"> | |
| <div class="ach-ic">${a.icon}</div> | |
| <div><div class="ach-nm">${a.name} ${on?'โ ':''}</div><div class="ach-ds">${a.desc}</div></div> | |
| </div>`; | |
| }).join(''); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| STATS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function renderStats(score, prod, risk){ | |
| document.getElementById('prof-stats').innerHTML=` | |
| <div class="st-row"><span>Total Analyses</span><span class="st-v">${S.history?S.history.length:1}</span></div> | |
| <div class="st-row"><span>Current Score</span><span class="st-v">${score}</span></div> | |
| <div class="st-row"><span>Productivity</span><span class="st-v">${prod}%</span></div> | |
| <div class="st-row"><span>Risk Level</span><span class="st-v">${risk}%</span></div> | |
| <div class="st-row"><span>Total XP</span><span class="st-v">${S.xp||0}</span></div> | |
| <div class="st-row"><span>Best Streak</span><span class="st-v">${S.streak||0} days</span></div> | |
| `; | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| TABS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function showTab(name){ | |
| document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active')); | |
| document.querySelectorAll('.nb').forEach(b=>b.classList.remove('active')); | |
| document.getElementById('tab-'+name).classList.add('active'); | |
| document.getElementById('nb-'+name).classList.add('active'); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| TOAST | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function showToast(msg, dur=3200){ | |
| const t = document.getElementById('toast'); | |
| if(!t) return; | |
| // Play sound | |
| sounds.pop.currentTime = 0; | |
| sounds.pop.play(); | |
| t.textContent = msg; | |
| t.classList.add('show'); | |
| setTimeout(() => t.classList.remove('show'), dur); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| SARCASTIC NOTIFICATIONS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| const NOTIFS=[ | |
| 'Hey, your phone misses you. Actually no, it doesn\'t. ๐ต', | |
| 'Your study notes won\'t read themselves. Or will they? ๐ค', | |
| 'Notification from: Reality. You have work to do.', | |
| 'Focus check: still alive? Put the phone down.', | |
| 'Your productivity just texted. It\'s lonely.', | |
| 'Average Indian student scrolls 3hrs/day. Don\'t be average.', | |
| 'Your future self is watching. Don\'t disappoint them. ๐', | |
| ]; | |
| function scheduleNotif(score){ | |
| if(!document.getElementById('notif-tog').checked) return; | |
| if(score>50) showToast('๐ '+rnd(NOTIFS)); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| THEME | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function toggleTheme(){ | |
| S.darkMode=!S.darkMode; | |
| document.body.classList.toggle('light',!S.darkMode); | |
| document.getElementById('theme-toggle' ) && (document.querySelector('.ico-btn').textContent=S.darkMode?'๐':'โ๏ธ'); | |
| const tog=document.getElementById('dark-tog'); | |
| if(tog) tog.checked=S.darkMode; | |
| save(); | |
| } | |
| function toggleThemeCheck(el){ | |
| S.darkMode=el.checked; | |
| document.body.classList.toggle('light',!S.darkMode); | |
| save(); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| RESET | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function rerun(){ | |
| inpIdx=0; S.inputs={study:4,phone:3,social:2,sleep:7,notifications:50}; | |
| showScreen('s-input'); initInputs(); | |
| } | |
| function clearAll(){ | |
| if(!confirm('Reset all data? This cannot be undone.')) return; | |
| localStorage.removeItem('diq'); | |
| location.reload(); | |
| } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| UTILS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function rnd(arr){ return arr[Math.floor(Math.random()*arr.length)]; } | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| INIT | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| window.addEventListener('DOMContentLoaded', () => { | |
| load(); | |
| if (S.darkMode === false) document.body.classList.add('light'); | |
| if (S.name) { | |
| document.getElementById('name-in').value = S.name; | |
| } | |
| // Enter key on login | |
| document.getElementById('name-in').addEventListener('keydown', e => { | |
| if (e.key === 'Enter') doLogin(); | |
| }); | |
| // If returning user with results, go straight to dash | |
| if (S.name && S.results && S.quizDone) { | |
| document.getElementById('greeting').textContent = `Welcome back, ${S.name}! ๐`; | |
| showScreen('s-dash'); | |
| processResults(S.results); | |
| showTab('home'); | |
| } | |
| // --- TRAP BUTTON LOGIC (Sabke liye kaam karega) --- | |
| const trapBtn = document.getElementById('trap-btn'); | |
| if (trapBtn) { | |
| trapBtn.addEventListener('click', () => { | |
| sounds.pop.currentTime = 0; | |
| sounds.pop.play(); | |
| document.body.classList.add('trap-flash'); | |
| setTimeout(() => document.body.classList.remove('trap-flash'), 500); | |
| const msg = trapRoasts[Math.floor(Math.random() * trapRoasts.length)]; | |
| showToast(msg); | |
| }); | |
| } | |
| }); | |
| // 1. Sarcastic Messages ka Database | |
| const sarcasticVault = { | |
| high: ["Focus gaya tel lene ๐ญ", "Productivity just left the chat.", "เคเคคเคจเคพ scrolling? Dedication galat jagah pe hai.", "Phone se relationship strong haiโฆ future se weak."], | |
| medium: ["Youโre almost productive. Almost.", "Half focus, half nonsense. Balanced life?", "Scrolling kam, kaam thoda zyada?", "Potential haiโฆ use kab karoge?"], | |
| low: ["Who are you and why are you so productive?", "Suspiciously impressive. Character development!", "Focus level: main character energy.", "Is thisโฆ discipline? ๐ณ"], | |
| random: ["เคฌเฅเคฐเฅเค เคฒเคฟเคฏเคพ เคฅเคพ เคฏเคพ retirement?", "Motivation bufferingโฆ please wait.", "เคซเฅเคจ เคฐเคเฅ. Future เคเค เคพเค.", "เคเคพเคฎ pending hai, attitude full hai ๐ญ"] | |
| }; | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| SMART SARCASTIC NOTIFICATIONS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| SMART SARCASTIC NOTIFICATIONS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| function popSarcasticNotif() { | |
| // Only roast if the user is logged in and the dashboard is active | |
| const dashActive = document.getElementById('s-dash').classList.contains('active'); | |
| if (!S.name || !S.quizDone || !dashActive) return; | |
| const toast = document.getElementById('toast'); | |
| if(!toast) return; | |
| // Determine roast category based on the latest distraction score | |
| let type = 'random'; | |
| if (S.results) { | |
| const score = S.results.score; | |
| type = score > 75 ? 'high' : score > 45 ? 'medium' : 'low'; | |
| } | |
| const messages = sarcasticVault[type] || sarcasticVault.random; | |
| const msg = messages[Math.floor(Math.random() * messages.length)]; | |
| // Severity-based accent colors | |
| const colors = { high: "#ef4444", medium: "#f59e0b", low: "#10b981", random: "#8b5cf6" }; | |
| const color = colors[type] || colors.random; | |
| // Audio cue | |
| sounds.pop.currentTime = 0; | |
| sounds.pop.play(); | |
| toast.innerText = "๐ " + msg; | |
| toast.style.borderLeft = `6px solid ${color}`; | |
| toast.classList.add('show'); | |
| setTimeout(() => toast.classList.remove('show'), 4000); | |
| } | |
| // Start the roast engine | |
| // Set to 20s to balance humor without being annoying | |
| setInterval(popSarcasticNotif, 20000); | |
| /* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| DEBUG & LOGS | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ | |
| console.log("๐ DistractIQ Engine: Active & Ready to Roast."); | |