{"version":3,"file":"music-3RpwnBIV.js","sources":["../../../ui/src/stores/project-store.ts","../../../ui/src/utilities/confetti.ts"],"sourcesContent":["import { defineStore } from 'pinia';\nimport { useUserStore } from '~/stores/user-store';\nimport pyscriptApi from '~/utilities/pyscript-api';\nimport type { Project, Version } from '~/utilities/pyscript-api-models';\n\nconst userStore = useUserStore();\n\ninterface State {\n project: Project | null;\n versions: Version[];\n}\n\n/**\n * Stores the current project being edited or viewed, as well as its versions.\n */\nexport const useProjectStore = defineStore('project', {\n state: (): State => ({\n project: null,\n versions: [],\n }),\n\n getters: {\n /**\n * Determine if the current user is the owner of the project.\n */\n isProjectOwner(state) {\n if (userStore.isLoggedIn === false || state.project === null) {\n return false;\n }\n\n return (\n state.project.user_id === userStore.user?.id ||\n state.project.username === userStore.user?.username\n );\n },\n },\n\n actions: {\n /**\n * Fetch a project by its slug or id.\n */\n async fetchProjectAndVersions(usernameOrUserId: string, projectSlugOrId: string) {\n const uuidPattern =\n /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;\n\n if (uuidPattern.test(projectSlugOrId)) {\n this.project = await pyscriptApi.getProject(projectSlugOrId);\n } else {\n this.project = await pyscriptApi.getProjectBySlug(usernameOrUserId, projectSlugOrId);\n }\n\n await this.fetchVersions(this.project.id);\n },\n\n /**\n * Fetch a project's versions.\n */\n async fetchVersions(projectId: string) {\n const versions = await pyscriptApi.listVersions(projectId);\n this.versions = versions.sort((a, b) => {\n if (a.version !== 'latest' && b.version === 'latest') return 1;\n if (a.version === 'latest' && b.version !== 'latest') return -1;\n return Date.parse(b.created_at) - Date.parse(a.created_at);\n });\n },\n },\n});\n","/**\n * After reviewing many confetti animations, the best one was a vanilla JS\n * script that was created in 2019. It's a bit outdated, and could definitely\n * use some work. I haven't touched much of it other than removing the IIFE,\n * turning it into a TS module, and all vars were converted to let and const.\n * @see https://www.cssscript.com/confetti-falling-animation/\n *\n * The goal was to make something similar to Github's confetti falling that\n * appears when signing up for GitHub Copilot.\n * @see https://github.com/github-copilot/signup/success\n */\nexport function confetti() {\n const maxParticleCount = 150; // set max confetti count\n const particleSpeed = 2; // set the particle animation speed\n const startConfetti = startConfettiInner; // call to start confetti animation\n const stopConfetti = stopConfettiInner; // call to stop adding confetti\n const toggleConfetti = toggleConfettiInner; // call to start or stop the confetti animation depending on whether it's already running\n const removeConfetti = removeConfettiInner; // call to stop the confetti animation and remove all confetti immediately\n const colors = [\n 'DodgerBlue',\n 'OliveDrab',\n 'Gold',\n 'Pink',\n 'SlateBlue',\n 'LightBlue',\n 'Violet',\n 'PaleGreen',\n 'SteelBlue',\n 'SandyBrown',\n 'Chocolate',\n 'Crimson',\n ];\n let streamingConfetti = false;\n let animationTimer = null;\n let particles = [];\n let waveAngle = 0;\n\n function resetParticle(particle, width, height) {\n particle.color = colors[(Math.random() * colors.length) | 0];\n particle.x = Math.random() * width;\n particle.y = Math.random() * height - height;\n particle.diameter = Math.random() * 10 + 5;\n particle.tilt = Math.random() * 10 - 10;\n particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;\n particle.tiltAngle = 0;\n return particle;\n }\n\n function startConfettiInner() {\n const width = window.innerWidth;\n const height = window.innerHeight;\n window.requestAnimFrame = (function () {\n return (\n window.requestAnimationFrame ||\n window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame ||\n window.oRequestAnimationFrame ||\n window.msRequestAnimationFrame ||\n function (callback) {\n return window.setTimeout(callback, 16.6666667);\n }\n );\n })();\n let canvas = document.getElementById('confetti-canvas');\n if (canvas === null) {\n canvas = document.createElement('canvas');\n canvas.setAttribute('id', 'confetti-canvas');\n canvas.setAttribute(\n 'style',\n 'display:block;z-index:999999;pointer-events:none;position:fixed;top:0;right:0;bottom:0;left:0;',\n );\n document.body.appendChild(canvas);\n canvas.width = width;\n canvas.height = height;\n window.addEventListener(\n 'resize',\n function () {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n },\n true,\n );\n }\n const context = canvas.getContext('2d');\n while (particles.length < maxParticleCount) particles.push(resetParticle({}, width, height));\n streamingConfetti = true;\n if (animationTimer === null) {\n (function runAnimation() {\n context.clearRect(0, 0, window.innerWidth, window.innerHeight);\n if (particles.length === 0) animationTimer = null;\n else {\n updateParticles();\n drawParticles(context);\n animationTimer = requestAnimFrame(runAnimation);\n }\n })();\n }\n }\n\n function stopConfettiInner() {\n streamingConfetti = false;\n }\n\n function removeConfettiInner() {\n stopConfetti();\n particles = [];\n }\n\n function toggleConfettiInner() {\n if (streamingConfetti) stopConfettiInner();\n else startConfettiInner();\n }\n\n function drawParticles(context) {\n let particle;\n let x;\n for (let i = 0; i < particles.length; i++) {\n particle = particles[i];\n context.beginPath();\n context.lineWidth = particle.diameter;\n context.strokeStyle = particle.color;\n x = particle.x + particle.tilt;\n context.moveTo(x + particle.diameter / 2, particle.y);\n context.lineTo(x, particle.y + particle.tilt + particle.diameter / 2);\n context.stroke();\n }\n }\n\n function updateParticles() {\n const width = window.innerWidth;\n const height = window.innerHeight;\n let particle;\n waveAngle += 0.01;\n for (let i = 0; i < particles.length; i++) {\n particle = particles[i];\n if (!streamingConfetti && particle.y < -15) particle.y = height + 100;\n else {\n particle.tiltAngle += particle.tiltAngleIncrement;\n particle.x += Math.sin(waveAngle);\n particle.y += (Math.cos(waveAngle) + particle.diameter + particleSpeed) * 0.5;\n particle.tilt = Math.sin(particle.tiltAngle) * 15;\n }\n if (particle.x > width + 20 || particle.x < -20 || particle.y > height) {\n if (streamingConfetti && particles.length <= maxParticleCount)\n resetParticle(particle, width, height);\n else {\n particles.splice(i, 1);\n i--;\n }\n }\n }\n }\n\n return {\n startConfetti,\n stopConfetti,\n toggleConfetti,\n removeConfetti,\n };\n}\n"],"names":["userStore","useUserStore","useProjectStore","defineStore","state","_a","_b","usernameOrUserId","projectSlugOrId","pyscriptApi","projectId","versions","b","confetti","startConfetti","startConfettiInner","stopConfetti","stopConfettiInner","toggleConfetti","toggleConfettiInner","removeConfetti","removeConfettiInner","colors","streamingConfetti","animationTimer","particles","waveAngle","resetParticle","particle","width","height","callback","canvas","context","runAnimation","updateParticles","drawParticles","x"],"mappings":"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"}