Fireworks na oknie wygranej i zamykanie modala
This commit is contained in:
@@ -1,11 +1,55 @@
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import { Fireworks } from 'fireworks-js';
|
||||
import { usePuzzleStore } from '@/stores/puzzle';
|
||||
|
||||
const store = usePuzzleStore();
|
||||
const fireworksRef = ref(null);
|
||||
let fireworksInstance = null;
|
||||
|
||||
const handleClose = () => {
|
||||
store.closeWinModal();
|
||||
};
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (fireworksRef.value) {
|
||||
fireworksInstance = new Fireworks(fireworksRef.value, {
|
||||
autoresize: true,
|
||||
opacity: 0.6,
|
||||
acceleration: 1.05,
|
||||
friction: 0.98,
|
||||
gravity: 1.4,
|
||||
particles: 60,
|
||||
traceLength: 3,
|
||||
traceSpeed: 10,
|
||||
explosion: 5,
|
||||
intensity: 35,
|
||||
flickering: 60,
|
||||
hue: { min: 170, max: 210 },
|
||||
delay: { min: 20, max: 40 },
|
||||
rocketsPoint: { min: 50, max: 50 }
|
||||
});
|
||||
fireworksInstance.start();
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
fireworksInstance?.stop(true);
|
||||
fireworksInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-overlay" @click.self="handleClose">
|
||||
<div ref="fireworksRef" class="fireworks-layer"></div>
|
||||
<div class="modal glass-panel">
|
||||
<h2>GRATULACJE!</h2>
|
||||
<p>Rozwiązałeś zagadkę!</p>
|
||||
@@ -40,6 +84,15 @@ const store = usePuzzleStore();
|
||||
animation: fadeIn 0.5s ease;
|
||||
}
|
||||
|
||||
.fireworks-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal {
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
@@ -48,6 +101,8 @@ const store = usePuzzleStore();
|
||||
border: 1px solid var(--primary-accent);
|
||||
box-shadow: 0 0 50px rgba(0, 242, 255, 0.2);
|
||||
animation: slideUp 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ref } from 'vue';
|
||||
import { usePuzzleStore } from '@/stores/puzzle';
|
||||
import confetti from 'canvas-confetti';
|
||||
|
||||
export function useNonogram() {
|
||||
const store = usePuzzleStore();
|
||||
@@ -49,7 +48,6 @@ export function useNonogram() {
|
||||
const stopDrag = () => {
|
||||
isDragging.value = false;
|
||||
dragMode.value = null;
|
||||
checkWinEffect();
|
||||
};
|
||||
|
||||
const applyDrag = (r, c) => {
|
||||
@@ -86,38 +84,6 @@ export function useNonogram() {
|
||||
store.setCell(r, c, dragMode.value);
|
||||
};
|
||||
|
||||
const checkWinEffect = () => {
|
||||
if (store.isGameWon) {
|
||||
triggerConfetti();
|
||||
}
|
||||
};
|
||||
|
||||
const triggerConfetti = () => {
|
||||
const duration = 3000;
|
||||
const end = Date.now() + duration;
|
||||
|
||||
(function frame() {
|
||||
confetti({
|
||||
particleCount: 5,
|
||||
angle: 60,
|
||||
spread: 55,
|
||||
origin: { x: 0 },
|
||||
colors: ['#00f2ff', '#ff0055', '#ffffff']
|
||||
});
|
||||
confetti({
|
||||
particleCount: 5,
|
||||
angle: 120,
|
||||
spread: 55,
|
||||
origin: { x: 1 },
|
||||
colors: ['#00f2ff', '#ff0055', '#ffffff']
|
||||
});
|
||||
|
||||
if (Date.now() < end) {
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
}());
|
||||
};
|
||||
|
||||
return {
|
||||
startDrag,
|
||||
onMouseEnter,
|
||||
|
||||
@@ -324,6 +324,12 @@ export const usePuzzleStore = defineStore('puzzle', () => {
|
||||
}
|
||||
}
|
||||
|
||||
function closeWinModal() {
|
||||
if (!isGameWon.value) return;
|
||||
isGameWon.value = false;
|
||||
saveState();
|
||||
}
|
||||
|
||||
return {
|
||||
currentLevelId,
|
||||
solution,
|
||||
@@ -340,7 +346,8 @@ export const usePuzzleStore = defineStore('puzzle', () => {
|
||||
checkWin,
|
||||
loadState, // expose loadState
|
||||
moves,
|
||||
undo
|
||||
undo,
|
||||
closeWinModal
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user