Neuste Version
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const COLORS = [
|
||||
"#f43f5e", "#ec4899", "#d946ef", "#a855f7", "#8b5cf6",
|
||||
"#6366f1", "#3b82f6", "#0ea5e9", "#06b6d4", "#14b8a6",
|
||||
"#10b981", "#22c55e", "#84cc16", "#eab308", "#f97316"
|
||||
];
|
||||
|
||||
const SHAPES = ["circle", "square", "triangle"];
|
||||
|
||||
export default function Confetti({ count = 80 }) {
|
||||
const [particles, setParticles] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const generated = Array.from({ length: count }).map((_, idx) => {
|
||||
const size = Math.random() * 8 + 6; // 6px - 14px
|
||||
const color = COLORS[Math.floor(Math.random() * COLORS.length)];
|
||||
const shape = SHAPES[Math.floor(Math.random() * SHAPES.length)];
|
||||
const left = Math.random() * 100; // 0% - 100%
|
||||
const delay = Math.random() * 4; // 0s - 4s delay
|
||||
const duration = Math.random() * 3 + 3; // 3s - 6s duration
|
||||
const rotation = Math.random() * 360;
|
||||
|
||||
return {
|
||||
id: idx,
|
||||
size,
|
||||
color,
|
||||
shape,
|
||||
left: `${left}%`,
|
||||
delay: `${delay}s`,
|
||||
duration: `${duration}s`,
|
||||
rotation: `${rotation}deg`
|
||||
};
|
||||
});
|
||||
|
||||
setParticles(generated);
|
||||
}, [count]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{`
|
||||
@keyframes confetti-fall {
|
||||
0% {
|
||||
transform: translateY(-20px) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(105vh) rotate(720deg);
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
@keyframes confetti-sway {
|
||||
0%, 100% {
|
||||
transform: translateX(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(50px);
|
||||
}
|
||||
}
|
||||
.confetti-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
overflow: hidden;
|
||||
}
|
||||
.confetti-particle {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
animation-name: confetti-fall;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
.confetti-swayer {
|
||||
animation: confetti-sway 3s ease-in-out infinite alternate;
|
||||
}
|
||||
`}</style>
|
||||
<div className="confetti-container">
|
||||
{particles.map((p) => {
|
||||
let style = {
|
||||
width: `${p.size}px`,
|
||||
height: `${p.size}px`,
|
||||
backgroundColor: p.shape !== "triangle" ? p.color : "transparent",
|
||||
left: p.left,
|
||||
animationDelay: p.delay,
|
||||
animationDuration: p.duration,
|
||||
transform: `rotate(${p.rotation})`,
|
||||
};
|
||||
|
||||
if (p.shape === "circle") {
|
||||
style.borderRadius = "50%";
|
||||
} else if (p.shape === "triangle") {
|
||||
style.width = "0";
|
||||
style.height = "0";
|
||||
style.borderLeft = `${p.size / 2}px solid transparent`;
|
||||
style.borderRight = `${p.size / 2}px solid transparent`;
|
||||
style.borderBottom = `${p.size}px solid ${p.color}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={p.id}
|
||||
className="confetti-particle"
|
||||
style={style}
|
||||
>
|
||||
<div className="confetti-swayer" style={{ width: "100%", height: "100%" }} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
|
||||
export default function QuestionCard({ frage, antworten, onNext, isLast }) {
|
||||
export default function QuestionCard({ frage, antworten, onNext, onCheck, isLast }) {
|
||||
const [selected, setSelected] = useState([]);
|
||||
const [checked, setChecked] = useState(false); // wurde „Überprüfen“ gedrückt
|
||||
|
||||
@@ -17,7 +17,15 @@ export default function QuestionCard({ frage, antworten, onNext, isLast }) {
|
||||
const isCorrect = (idx) => antworten[idx].korrekt;
|
||||
const wasSelected = (idx) => selected.includes(idx);
|
||||
|
||||
const handleCheck = () => setChecked(true);
|
||||
const handleCheck = () => {
|
||||
setChecked(true);
|
||||
const correct = antworten.every((antwort, idx) => {
|
||||
return antwort.korrekt === selected.includes(idx);
|
||||
});
|
||||
if (onCheck) {
|
||||
onCheck(correct);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
setSelected([]);
|
||||
@@ -26,7 +34,7 @@ export default function QuestionCard({ frage, antworten, onNext, isLast }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-6 rounded-xl shadow-lg transition transform hover:-translate-y-1 hover:shadow-xl">
|
||||
<div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 p-6 rounded-xl shadow-lg transition transform hover:-translate-y-1 hover:shadow-xl animate-float-in">
|
||||
<h2 className="text-lg font-semibold mb-4">{frage}</h2>
|
||||
<div className="space-y-2">
|
||||
{antworten.map((antwort, idx) => {
|
||||
|
||||
Reference in New Issue
Block a user