Fireworks na oknie wygranej i zamykanie modala
This commit is contained in:
18
package-lock.json
generated
18
package-lock.json
generated
@@ -8,7 +8,7 @@
|
|||||||
"name": "vue-nonograms-solid",
|
"name": "vue-nonograms-solid",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas-confetti": "^1.9.2",
|
"fireworks-js": "^2.10.8",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "^3.4.19"
|
"vue": "^3.4.19"
|
||||||
},
|
},
|
||||||
@@ -937,16 +937,6 @@
|
|||||||
"integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==",
|
"integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/canvas-confetti": {
|
|
||||||
"version": "1.9.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.4.tgz",
|
|
||||||
"integrity": "sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==",
|
|
||||||
"license": "ISC",
|
|
||||||
"funding": {
|
|
||||||
"type": "donate",
|
|
||||||
"url": "https://www.paypal.me/kirilvatev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
@@ -1010,6 +1000,12 @@
|
|||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/fireworks-js": {
|
||||||
|
"version": "2.10.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/fireworks-js/-/fireworks-js-2.10.8.tgz",
|
||||||
|
"integrity": "sha512-UZNxeJvRmQzLisN4iriWXqKojG9TDJqc0dPmkUw0/+AEQQ3w8z1Jx2YdFSiBGSVb/u4dPTQXU109GMVblzhfpg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"fireworks-js": "^2.10.8",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "^3.4.19",
|
"vue": "^3.4.19"
|
||||||
"canvas-confetti": "^1.9.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"vite": "^5.1.4"
|
"vite": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,55 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
import { Fireworks } from 'fireworks-js';
|
||||||
import { usePuzzleStore } from '@/stores/puzzle';
|
import { usePuzzleStore } from '@/stores/puzzle';
|
||||||
|
|
||||||
const store = usePuzzleStore();
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="modal-overlay">
|
<div class="modal-overlay" @click.self="handleClose">
|
||||||
|
<div ref="fireworksRef" class="fireworks-layer"></div>
|
||||||
<div class="modal glass-panel">
|
<div class="modal glass-panel">
|
||||||
<h2>GRATULACJE!</h2>
|
<h2>GRATULACJE!</h2>
|
||||||
<p>Rozwiązałeś zagadkę!</p>
|
<p>Rozwiązałeś zagadkę!</p>
|
||||||
@@ -40,6 +84,15 @@ const store = usePuzzleStore();
|
|||||||
animation: fadeIn 0.5s ease;
|
animation: fadeIn 0.5s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fireworks-layer {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -48,6 +101,8 @@ const store = usePuzzleStore();
|
|||||||
border: 1px solid var(--primary-accent);
|
border: 1px solid var(--primary-accent);
|
||||||
box-shadow: 0 0 50px rgba(0, 242, 255, 0.2);
|
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);
|
animation: slideUp 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
position: relative;
|
||||||
|
z-index: 1001;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { usePuzzleStore } from '@/stores/puzzle';
|
import { usePuzzleStore } from '@/stores/puzzle';
|
||||||
import confetti from 'canvas-confetti';
|
|
||||||
|
|
||||||
export function useNonogram() {
|
export function useNonogram() {
|
||||||
const store = usePuzzleStore();
|
const store = usePuzzleStore();
|
||||||
@@ -49,7 +48,6 @@ export function useNonogram() {
|
|||||||
const stopDrag = () => {
|
const stopDrag = () => {
|
||||||
isDragging.value = false;
|
isDragging.value = false;
|
||||||
dragMode.value = null;
|
dragMode.value = null;
|
||||||
checkWinEffect();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyDrag = (r, c) => {
|
const applyDrag = (r, c) => {
|
||||||
@@ -86,38 +84,6 @@ export function useNonogram() {
|
|||||||
store.setCell(r, c, dragMode.value);
|
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 {
|
return {
|
||||||
startDrag,
|
startDrag,
|
||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
|
|||||||
@@ -324,6 +324,12 @@ export const usePuzzleStore = defineStore('puzzle', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeWinModal() {
|
||||||
|
if (!isGameWon.value) return;
|
||||||
|
isGameWon.value = false;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentLevelId,
|
currentLevelId,
|
||||||
solution,
|
solution,
|
||||||
@@ -340,7 +346,8 @@ export const usePuzzleStore = defineStore('puzzle', () => {
|
|||||||
checkWin,
|
checkWin,
|
||||||
loadState, // expose loadState
|
loadState, // expose loadState
|
||||||
moves,
|
moves,
|
||||||
undo
|
undo,
|
||||||
|
closeWinModal
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user