mirror of
https://github.com/randyjc/Rahoot.git
synced 2026-03-13 20:15:35 +01:00
Update Podium & Statred to add sound
This commit is contained in:
39
package-lock.json
generated
39
package-lock.json
generated
@@ -11,10 +11,12 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"next": "14.1.0",
|
"next": "14.1.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
"react-confetti": "^6.1.0",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"socket.io": "^4.7.4",
|
"socket.io": "^4.7.4",
|
||||||
"socket.io-client": "^4.7.4"
|
"socket.io-client": "^4.7.4",
|
||||||
|
"use-sound": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
@@ -2422,6 +2424,11 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/howler": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w=="
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
|
||||||
@@ -3823,6 +3830,20 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-confetti": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tween-functions": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.3.0 || ^17.0.1 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
@@ -4610,6 +4631,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tween-functions": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
@@ -4772,6 +4798,17 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-sound": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sound/-/use-sound-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-hykJ86kNcu6y/FzlSHcQxhjSGMslZx2WlfLpZNoPbvueakv4OF3xPxEtGV2YmculrIaH0tPp9LtG4jgy17xMWg==",
|
||||||
|
"dependencies": {
|
||||||
|
"howler": "^2.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"next": "14.1.0",
|
"next": "14.1.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
"react-confetti": "^6.1.0",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"socket.io": "^4.7.4",
|
"socket.io": "^4.7.4",
|
||||||
"socket.io-client": "^4.7.4"
|
"socket.io-client": "^4.7.4",
|
||||||
|
"use-sound": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
|
|||||||
BIN
public/sounds/answersMusic.mp3
Normal file
BIN
public/sounds/answersMusic.mp3
Normal file
Binary file not shown.
BIN
public/sounds/answersSound.mp3
Normal file
BIN
public/sounds/answersSound.mp3
Normal file
Binary file not shown.
BIN
public/sounds/results.mp3
Normal file
BIN
public/sounds/results.mp3
Normal file
Binary file not shown.
BIN
public/sounds/show.mp3
Normal file
BIN
public/sounds/show.mp3
Normal file
Binary file not shown.
@@ -32,6 +32,11 @@ const Player = {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (game.players.find((p) => p.username === player.username)) {
|
||||||
|
socket.emit("game:errorMessage", "Username already exists")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (game.started) {
|
if (game.started) {
|
||||||
socket.emit("game:errorMessage", "Game already started")
|
socket.emit("game:errorMessage", "Game already started")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,7 +2,14 @@ import AnswerButton from "../../AnswerButton"
|
|||||||
import { useSocketContext } from "@/context/socket"
|
import { useSocketContext } from "@/context/socket"
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { ANSWERS_COLORS, ANSWERS_ICONS } from "@/constants"
|
import {
|
||||||
|
ANSWERS_COLORS,
|
||||||
|
ANSWERS_ICONS,
|
||||||
|
SFX_ANSWERS_MUSIC,
|
||||||
|
SFX_ANSWERS_SOUND,
|
||||||
|
SFX_RESULTS_SOUND,
|
||||||
|
} from "@/constants"
|
||||||
|
import useSound from "use-sound"
|
||||||
|
|
||||||
const calculatePercentages = (objectResponses) => {
|
const calculatePercentages = (objectResponses) => {
|
||||||
const keys = Object.keys(objectResponses)
|
const keys = Object.keys(objectResponses)
|
||||||
@@ -35,12 +42,32 @@ export default function Answers({
|
|||||||
const [cooldown, setCooldown] = useState(time)
|
const [cooldown, setCooldown] = useState(time)
|
||||||
const [totalAnswer, setTotalAnswer] = useState(0)
|
const [totalAnswer, setTotalAnswer] = useState(0)
|
||||||
|
|
||||||
|
const [sfxPop] = useSound(SFX_ANSWERS_SOUND, {
|
||||||
|
volume: 0.1,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [sfxResults] = useSound(SFX_RESULTS_SOUND, {
|
||||||
|
volume: 0.2,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [playMusic, { stop: stopMusic }] = useSound(SFX_ANSWERS_MUSIC, {
|
||||||
|
volume: 0.2,
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!responses) {
|
if (!responses) {
|
||||||
|
playMusic()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopMusic()
|
||||||
|
sfxResults()
|
||||||
|
|
||||||
setPercentages(calculatePercentages(responses))
|
setPercentages(calculatePercentages(responses))
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
stopMusic()
|
||||||
|
}
|
||||||
}, [responses])
|
}, [responses])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -50,6 +77,7 @@ export default function Answers({
|
|||||||
|
|
||||||
socket.on("game:playerAnswer", (count) => {
|
socket.on("game:playerAnswer", (count) => {
|
||||||
setTotalAnswer(count)
|
setTotalAnswer(count)
|
||||||
|
sfxPop()
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -123,9 +151,3 @@ export default function Answers({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OLD Timer
|
|
||||||
<div className="absolute left-8 -translate-y-1/2 top-2/4 text-white font-bold text-6xl rounded-full justify-center items-center bg-orange-400 p-8 aspect-square hidden 2xl:flex">
|
|
||||||
<span </div>className="drop-shadow-md">20</span>
|
|
||||||
</div>
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import Loader from "@/components/Loader"
|
import Loader from "@/components/Loader"
|
||||||
|
import useScreenSize from "@/hook/useScreenSize"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
import ReactConfetti from "react-confetti"
|
||||||
|
|
||||||
export default function Podium({ data: { subject, top } }) {
|
export default function Podium({ data: { subject, top } }) {
|
||||||
const [apparition, setApparition] = useState(0)
|
const [apparition, setApparition] = useState(0)
|
||||||
|
|
||||||
|
const { width, height } = useScreenSize()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (top.length < 3) {
|
if (top.length < 3) {
|
||||||
setApparition(4)
|
setApparition(4)
|
||||||
@@ -22,22 +26,43 @@ export default function Podium({ data: { subject, top } }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{apparition >= 4 && (
|
||||||
|
<ReactConfetti
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
className="h-full w-full"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{apparition >= 3 && top.length >= 3 && (
|
||||||
|
<div className="absolute min-h-screen w-full overflow-hidden">
|
||||||
|
<div className="spotlight"></div>{" "}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<section className="relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-between">
|
<section className="relative mx-auto flex w-full max-w-7xl flex-1 flex-col items-center justify-between">
|
||||||
<h2 className="anim-show text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
<h2 className="anim-show text-center text-3xl font-bold text-white drop-shadow-lg md:text-4xl lg:text-5xl">
|
||||||
{subject}
|
{subject}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`grid max-w-[500px] flex-1 grid-cols-${top.length} w-full items-end justify-center justify-self-end overflow-x-visible`}
|
className={`grid w-full max-w-[800px] flex-1 grid-cols-3 items-end justify-center justify-self-end overflow-y-hidden overflow-x-visible`}
|
||||||
>
|
>
|
||||||
{top[1] && (
|
{top[1] && (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"z-20 flex h-[50%] w-full flex-col items-center justify-center gap-3 opacity-0",
|
"z-20 flex h-[50%] w-full translate-y-full flex-col items-center justify-center gap-3 opacity-0 transition-all",
|
||||||
{ "opacity-100": apparition >= 2 },
|
{ "translate-y-0 opacity-100": apparition >= 2 },
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className={clsx(
|
||||||
|
"overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white drop-shadow-lg md:text-4xl",
|
||||||
|
{
|
||||||
|
"anim-balanced": apparition >= 4,
|
||||||
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p className="overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white drop-shadow-lg">
|
|
||||||
{top[1].username}
|
{top[1].username}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex h-full w-full flex-col items-center gap-4 rounded-t-md bg-primary pt-6 text-center shadow-2xl">
|
<div className="flex h-full w-full flex-col items-center gap-4 rounded-t-md bg-primary pt-6 text-center shadow-2xl">
|
||||||
@@ -53,9 +78,9 @@ export default function Podium({ data: { subject, top } }) {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"z-30 flex h-[60%] w-full flex-col items-center gap-3 opacity-0",
|
"z-30 flex h-[60%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
||||||
{
|
{
|
||||||
"opacity-100": apparition >= 3,
|
"translate-y-0 opacity-100": apparition >= 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"md:min-w-64": top.length < 2,
|
"md:min-w-64": top.length < 2,
|
||||||
@@ -64,8 +89,8 @@ export default function Podium({ data: { subject, top } }) {
|
|||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white opacity-0 drop-shadow-lg",
|
"overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white opacity-0 drop-shadow-lg md:text-4xl",
|
||||||
{ "opacity-100": apparition >= 4 },
|
{ "anim-balanced opacity-100": apparition >= 4 },
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{top[0].username}
|
{top[0].username}
|
||||||
@@ -83,13 +108,20 @@ export default function Podium({ data: { subject, top } }) {
|
|||||||
{top[2] && (
|
{top[2] && (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"z-10 flex h-[40%] w-full flex-col items-center gap-3 opacity-0",
|
"z-10 flex h-[40%] w-full translate-y-full flex-col items-center gap-3 opacity-0 transition-all",
|
||||||
{
|
{
|
||||||
"opacity-100": apparition >= 1,
|
"translate-y-0 opacity-100": apparition >= 1,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className={clsx(
|
||||||
|
"overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white drop-shadow-lg md:text-4xl",
|
||||||
|
{
|
||||||
|
"anim-balanced": apparition >= 4,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p className="overflow-visible whitespace-nowrap text-center text-2xl font-bold text-white drop-shadow-lg">
|
|
||||||
{top[2].username}
|
{top[2].username}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex h-full w-full flex-col items-center gap-4 rounded-t-md bg-primary pt-6 text-center shadow-2xl">
|
<div className="flex h-full w-full flex-col items-center gap-4 rounded-t-md bg-primary pt-6 text-center shadow-2xl">
|
||||||
@@ -105,5 +137,6 @@ export default function Podium({ data: { subject, top } }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import { useRef } from "react"
|
import { SFX_SHOW_SOUND } from "@/constants"
|
||||||
|
import { useEffect, useRef } from "react"
|
||||||
|
import useSound from "use-sound"
|
||||||
|
|
||||||
export default function Question({ data: { question, image, cooldown } }) {
|
export default function Question({ data: { question, image, cooldown } }) {
|
||||||
const barRef = useRef(null)
|
const [sfxShow] = useSound(SFX_SHOW_SOUND, { volume: 0.5 })
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sfxShow()
|
||||||
|
}, [sfxShow])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative mx-auto flex h-full w-full max-w-7xl flex-1 flex-col items-center px-4">
|
<section className="relative mx-auto flex h-full w-full max-w-7xl flex-1 flex-col items-center px-4">
|
||||||
@@ -15,7 +21,6 @@ export default function Question({ data: { question, image, cooldown } }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref={barRef}
|
|
||||||
className="mb-20 h-4 self-start justify-self-end rounded-full bg-primary"
|
className="mb-20 h-4 self-start justify-self-end rounded-full bg-primary"
|
||||||
style={{ animation: `progressBar ${cooldown}s linear forwards` }}
|
style={{ animation: `progressBar ${cooldown}s linear forwards` }}
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@@ -51,3 +51,8 @@ export const GAME_STATE_COMPONENTS_MANAGER = {
|
|||||||
SHOW_LEADERBOARD: Leaderboard,
|
SHOW_LEADERBOARD: Leaderboard,
|
||||||
FINISH: Podium,
|
FINISH: Podium,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SFX_ANSWERS_MUSIC = "/sounds/answersMusic.mp3"
|
||||||
|
export const SFX_ANSWERS_SOUND = "/sounds/answersSound.mp3"
|
||||||
|
export const SFX_RESULTS_SOUND = "/sounds/results.mp3"
|
||||||
|
export const SFX_SHOW_SOUND = "/sounds/show.mp3"
|
||||||
|
|||||||
26
src/hook/useScreenSize.js
Normal file
26
src/hook/useScreenSize.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useState, useEffect } from "react"
|
||||||
|
|
||||||
|
const useScreenSize = () => {
|
||||||
|
const [screenSize, setScreenSize] = useState({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setScreenSize({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", handleResize)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", handleResize)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return screenSize
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useScreenSize
|
||||||
@@ -32,6 +32,49 @@
|
|||||||
box-shadow: rgba(0, 0, 0, 0.25) 0px -4px inset;
|
box-shadow: rgba(0, 0, 0, 0.25) 0px -4px inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spotlight {
|
||||||
|
position: absolute;
|
||||||
|
height: 200%;
|
||||||
|
width: 200%;
|
||||||
|
z-index: 100;
|
||||||
|
background-image: radial-gradient(
|
||||||
|
circle,
|
||||||
|
transparent 180px,
|
||||||
|
rgba(0, 0, 0, 0.6) 200px
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
left: -50%;
|
||||||
|
top: -50%;
|
||||||
|
transition: all 0.5s;
|
||||||
|
animation: spotlightAnim 2.5s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spotlightAnim {
|
||||||
|
0% {
|
||||||
|
left: -20%;
|
||||||
|
top: -20%;
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
opacity: 100;
|
||||||
|
top: -80%;
|
||||||
|
left: -80%;
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
top: -50%;
|
||||||
|
left: -20%;
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
top: -50%;
|
||||||
|
left: -50%;
|
||||||
|
}
|
||||||
|
95% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.anim-show {
|
.anim-show {
|
||||||
animation: show 0.5s ease-out;
|
animation: show 0.5s ease-out;
|
||||||
}
|
}
|
||||||
@@ -52,6 +95,28 @@
|
|||||||
animation: quizzButton 0.8s ease-out;
|
animation: quizzButton 0.8s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.anim-balanced {
|
||||||
|
animation: balanced 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes balanced {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(-10deg) translateY(-10px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(0deg) translateY(0px);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(10deg) translateY(-10px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes show {
|
@keyframes show {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user