added animated move timer
This commit is contained in:
parent
e702b912f7
commit
6fef82f36a
@ -115,6 +115,7 @@ module.exports = (io, socket) => {
|
|||||||
socket.join(room._id.toString());
|
socket.join(room._id.toString());
|
||||||
// Sending data to the user, after which player will be redirected to the game
|
// Sending data to the user, after which player will be redirected to the game
|
||||||
socket.emit('player:data', JSON.stringify(req.session));
|
socket.emit('player:data', JSON.stringify(req.session));
|
||||||
|
socket.emit('room:data', JSON.stringify(updatedRoom));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,8 @@ module.exports = (io, socket) => {
|
|||||||
room.players[index + 1].nowMoving = true;
|
room.players[index + 1].nowMoving = true;
|
||||||
}
|
}
|
||||||
room.nextMoveTime = Date.now() + 15000;
|
room.nextMoveTime = Date.now() + 15000;
|
||||||
|
if (this.timeoutID) clearTimeout(this.timeoutID);
|
||||||
|
this.timeoutID = null;
|
||||||
RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, function (err, updatedRoom) {
|
RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, function (err, updatedRoom) {
|
||||||
io.to(req.session.roomId).emit('room:data', JSON.stringify(updatedRoom));
|
io.to(req.session.roomId).emit('room:data', JSON.stringify(updatedRoom));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -36,6 +36,7 @@ RoomSchema.methods.changeMovingPlayer = function () {
|
|||||||
this.nextMoveTime = Date.now() + 15000;
|
this.nextMoveTime = Date.now() + 15000;
|
||||||
this.rolledNumber = null;
|
this.rolledNumber = null;
|
||||||
if (this.timeoutID) clearTimeout(this.timeoutID);
|
if (this.timeoutID) clearTimeout(this.timeoutID);
|
||||||
|
this.timeoutID = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomSchema.methods.movePawn = function (pawn) {
|
RoomSchema.methods.movePawn = function (pawn) {
|
||||||
|
|||||||
27
package-lock.json
generated
27
package-lock.json
generated
@ -20,6 +20,7 @@
|
|||||||
"react-loading": "^2.0.3",
|
"react-loading": "^2.0.3",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
|
"react-transition-group": "^4.4.5",
|
||||||
"socket.io": "^4.5.1",
|
"socket.io": "^4.5.1",
|
||||||
"socket.io-client": "^4.5.1",
|
"socket.io-client": "^4.5.1",
|
||||||
"web-vitals": "^1.1.0"
|
"web-vitals": "^1.1.0"
|
||||||
@ -16735,9 +16736,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-transition-group": {
|
"node_modules/react-transition-group": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
|
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"dom-helpers": "^5.0.1",
|
"dom-helpers": "^5.0.1",
|
||||||
@ -18664,16 +18665,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.2.2",
|
"version": "4.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.17"
|
"node": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/unbox-primitive": {
|
"node_modules/unbox-primitive": {
|
||||||
@ -31757,9 +31758,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
|
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"dom-helpers": "^5.0.1",
|
"dom-helpers": "^5.0.1",
|
||||||
@ -33178,9 +33179,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "5.2.2",
|
"version": "4.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"unbox-primitive": {
|
"unbox-primitive": {
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"react-loading": "^2.0.3",
|
"react-loading": "^2.0.3",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
|
"react-transition-group": "^4.4.5",
|
||||||
"socket.io": "^4.5.1",
|
"socket.io": "^4.5.1",
|
||||||
"socket.io-client": "^4.5.1",
|
"socket.io-client": "^4.5.1",
|
||||||
"web-vitals": "^1.1.0"
|
"web-vitals": "^1.1.0"
|
||||||
|
|||||||
@ -40,9 +40,6 @@ function App() {
|
|||||||
<Gameboard />
|
<Gameboard />
|
||||||
</PlayerDataContext.Provider>
|
</PlayerDataContext.Provider>
|
||||||
) : null}
|
) : null}
|
||||||
<a href='https://www.flaticon.com/free-icons/hand' title='hand icons'>
|
|
||||||
Hand icons created by berkahicon - Flaticon
|
|
||||||
</a>
|
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
</Router>
|
||||||
|
|||||||
@ -67,8 +67,8 @@ const Gameboard = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{players ? (
|
{(players[0] && !started) || (time && started) ? (
|
||||||
<>
|
<div className='container'>
|
||||||
<Navbar
|
<Navbar
|
||||||
players={players}
|
players={players}
|
||||||
started={started}
|
started={started}
|
||||||
@ -80,7 +80,7 @@ const Gameboard = () => {
|
|||||||
rolledNumberCallback={rolledNumberCallback}
|
rolledNumberCallback={rolledNumberCallback}
|
||||||
/>
|
/>
|
||||||
<Map pawns={pawns} nowMoving={nowMoving} rolledNumber={rolledNumber} />
|
<Map pawns={pawns} nowMoving={nowMoving} rolledNumber={rolledNumber} />
|
||||||
</>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ReactLoading type='spinningBubbles' color='white' height={667} width={375} />
|
<ReactLoading type='spinningBubbles' color='white' height={667} width={375} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,26 +1,3 @@
|
|||||||
.red {
|
|
||||||
position: relative;
|
|
||||||
left: 176px;
|
|
||||||
}
|
|
||||||
.yellow {
|
|
||||||
position: relative;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
right: 170px;
|
|
||||||
}
|
|
||||||
.blue {
|
|
||||||
position: relative;
|
|
||||||
right: 28px;
|
|
||||||
top: 538px;
|
|
||||||
}
|
|
||||||
.green {
|
|
||||||
position: relative;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
top: 538px;
|
|
||||||
left: 36px;
|
|
||||||
}
|
|
||||||
.player-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.dice-container {
|
.dice-container {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
@ -30,3 +7,49 @@
|
|||||||
.roll {
|
.roll {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.ready-container {
|
||||||
|
display: flex;
|
||||||
|
width: 300px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-flow: row-reverse;
|
||||||
|
background-color: grey;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid white;
|
||||||
|
}
|
||||||
|
.ready-container > label {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 100px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.player-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.red {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
.yellow {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
flex-flow: row-reverse;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
margin-top: 50px;
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 4;
|
||||||
|
}
|
||||||
|
.green {
|
||||||
|
margin-top: 50px;
|
||||||
|
flex-flow: row-reverse;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 4;
|
||||||
|
}
|
||||||
|
/* Styl dla overlay */
|
||||||
|
|||||||
@ -3,11 +3,13 @@ import Dice from './game-board-components/Dice';
|
|||||||
import NameContainer from './navbar-components/NameContainer';
|
import NameContainer from './navbar-components/NameContainer';
|
||||||
import ReadyButton from './navbar-components/ReadyButton';
|
import ReadyButton from './navbar-components/ReadyButton';
|
||||||
import './Navbar.css';
|
import './Navbar.css';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { PlayerDataContext } from '../App';
|
||||||
const Navbar = ({ players, started, time, isReady, rolledNumber, nowMoving, rolledNumberCallback, movingPlayer }) => {
|
const Navbar = ({ players, started, time, isReady, rolledNumber, nowMoving, rolledNumberCallback, movingPlayer }) => {
|
||||||
|
const context = useContext(PlayerDataContext);
|
||||||
const colors = ['red', 'blue', 'green', 'yellow'];
|
const colors = ['red', 'blue', 'green', 'yellow'];
|
||||||
return (
|
return (
|
||||||
<div className='navbar-container'>
|
<>
|
||||||
{players.map((player, index) => (
|
{players.map((player, index) => (
|
||||||
<div className={`player-container ${colors[index]}`} key={index}>
|
<div className={`player-container ${colors[index]}`} key={index}>
|
||||||
<NameContainer player={player} time={time} />
|
<NameContainer player={player} time={time} />
|
||||||
@ -18,10 +20,10 @@ const Navbar = ({ players, started, time, isReady, rolledNumber, nowMoving, roll
|
|||||||
color={colors[index]}
|
color={colors[index]}
|
||||||
rolledNumberCallback={rolledNumberCallback}
|
rolledNumberCallback={rolledNumberCallback}
|
||||||
/>
|
/>
|
||||||
|
{context.color !== player.color || started ? null : <ReadyButton isReady={isReady} />}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{started ? null : <ReadyButton isReady={isReady} />}
|
</>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default Navbar;
|
export default Navbar;
|
||||||
|
|||||||
25
src/components/navbar-components/AnimatedOverlay.jsx
Normal file
25
src/components/navbar-components/AnimatedOverlay.jsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { CSSTransition } from 'react-transition-group';
|
||||||
|
import './TimerAnimation.js';
|
||||||
|
|
||||||
|
const AnimatedOverlay = ({ time }) => {
|
||||||
|
const [animationDelay, setAnimationDelay] = useState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAnimationDelay(15 - Math.ceil((time - Date.now()) / 1000));
|
||||||
|
}, [time]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CSSTransition
|
||||||
|
in={true}
|
||||||
|
timeout={0}
|
||||||
|
classNames='overlay'
|
||||||
|
style={{ 'animation-delay': `-${animationDelay}s` }}
|
||||||
|
unmountOnExit
|
||||||
|
>
|
||||||
|
<div className='overlay'></div>
|
||||||
|
</CSSTransition>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnimatedOverlay;
|
||||||
@ -1,51 +1,15 @@
|
|||||||
import React, { useState, useEffect, useContext } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { SocketContext } from '../../App';
|
import AnimatedOverlay from './AnimatedOverlay';
|
||||||
|
|
||||||
/*
|
|
||||||
Component responsible for:
|
|
||||||
- displaying the player's name
|
|
||||||
- informing players about the readiness of other players by changing the color of container from gray to the player's color
|
|
||||||
- counting time to the end of the move
|
|
||||||
|
|
||||||
Props:
|
|
||||||
- player (object):
|
|
||||||
The player to whom the container belongs
|
|
||||||
Player's properties used in this component:
|
|
||||||
- ready (boolean):
|
|
||||||
is the player ready for the start of the game, if so, change color from gray to the player's color
|
|
||||||
when the game is started all players are ready not matter if they clicked ready button before
|
|
||||||
- nowMoving (boolean) is this player move now, if true display timer
|
|
||||||
- name (string)
|
|
||||||
- time (number) - time remaining until the move is made in milliseconds
|
|
||||||
*/
|
|
||||||
|
|
||||||
const NameContainer = ({ player, time }) => {
|
const NameContainer = ({ player, time }) => {
|
||||||
const [remainingTime, setRemainingTime] = useState();
|
|
||||||
const socket = useContext(SocketContext);
|
|
||||||
|
|
||||||
// Function responsible for counting down to the end of time every second
|
|
||||||
const countdown = () => {
|
|
||||||
setRemainingTime(Math.ceil((time - Date.now()) / 1000));
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Starts the countdown from the beginning if the server returned information about skipping the turn
|
|
||||||
socket.on('game:skip', () => {
|
|
||||||
setRemainingTime(15);
|
|
||||||
});
|
|
||||||
setRemainingTime(Math.ceil((time - Date.now()) / 1000));
|
|
||||||
const interval = setInterval(countdown, 1000);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [countdown]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='name-container'
|
className='name-container'
|
||||||
style={player.ready ? { backgroundColor: player.color } : { backgroundColor: 'lightgrey' }}
|
style={player.ready ? { backgroundColor: player.color } : { backgroundColor: 'lightgrey' }}
|
||||||
>
|
>
|
||||||
<p>{player.name}</p>
|
<p>{player.name}</p>
|
||||||
{player.nowMoving ? <div className='timer'> {remainingTime} </div> : null}
|
{player.nowMoving ? <AnimatedOverlay time={time} /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React, { useState, useContext, useEffect } from 'react';
|
import React, { useState, useContext, useEffect } from 'react';
|
||||||
import { SocketContext } from '../../App';
|
import { SocketContext } from '../../App';
|
||||||
import Switch from '@material-ui/core/Switch';
|
import Switch from '@material-ui/core/Switch';
|
||||||
|
import '../Navbar.css';
|
||||||
|
import './TimerAnimation';
|
||||||
|
|
||||||
const ReadyButton = ({ isReady }) => {
|
const ReadyButton = ({ isReady }) => {
|
||||||
const socket = useContext(SocketContext);
|
const socket = useContext(SocketContext);
|
||||||
|
|||||||
63
src/components/navbar-components/TimerAnimation.js
Normal file
63
src/components/navbar-components/TimerAnimation.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
const keyframes = [];
|
||||||
|
const steps = 86;
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
let s = 'polygon(50% 50%, 50% 0%, 50% 0%';
|
||||||
|
|
||||||
|
for (let i = 50; i <= 100; i += 5) {
|
||||||
|
s += `, ${i}% 0%`;
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
for (let i = 0; i <= 100; i += 5) {
|
||||||
|
s += `, 100% ${i}%`;
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
for (let i = 100; i >= 0; i -= 5) {
|
||||||
|
s += `, ${i}% 100%`;
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 100; i >= 0; i -= 5) {
|
||||||
|
s += `, 0% ${i}%`;
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
for (let i = 0; i <= 50; i += 5) {
|
||||||
|
s += `, ${i}% 0%`;
|
||||||
|
handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle() {
|
||||||
|
const percentage = (count / steps) * 100;
|
||||||
|
let step;
|
||||||
|
if (percentage <= 75 && percentage >= 73) {
|
||||||
|
step = `${percentage}% {
|
||||||
|
background-color: orange;
|
||||||
|
clip-path: ${s})
|
||||||
|
}`;
|
||||||
|
} else if (percentage > 97.5 && percentage < 100) {
|
||||||
|
step = `${percentage}% {
|
||||||
|
background-color: red;
|
||||||
|
clip-path: ${s})
|
||||||
|
}`;
|
||||||
|
} else if (percentage > 0 && percentage < 2.5) {
|
||||||
|
step = `${percentage}% {
|
||||||
|
background-color: green;
|
||||||
|
clip-path: ${s})
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
step = `${percentage}% {
|
||||||
|
clip-path: ${s})
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
keyframes.push(step);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const animation = document.styleSheets[0].insertRule(
|
||||||
|
`
|
||||||
|
@keyframes timerAnimation {
|
||||||
|
${keyframes.join('\n')}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
document.styleSheets[0].cssRules.length
|
||||||
|
);
|
||||||
@ -6,13 +6,16 @@ body {
|
|||||||
rgba(0, 138, 255, 1) 16%,
|
rgba(0, 138, 255, 1) 16%,
|
||||||
rgba(9, 9, 121, 1) 81%
|
rgba(9, 9, 121, 1) 81%
|
||||||
);
|
);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
height: 100vh;
|
||||||
}
|
width: 100vw;
|
||||||
.canvas-container {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
border: 2px solid black;
|
border: 2px solid black;
|
||||||
@ -25,12 +28,14 @@ canvas {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
.navbar-container > div {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.name-container {
|
.name-container {
|
||||||
width: 100px;
|
position: relative;
|
||||||
height: 50px;
|
min-width: 100px;
|
||||||
|
min-height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
border: 2px solid white;
|
border: 2px solid white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: white;
|
color: white;
|
||||||
@ -49,9 +54,33 @@ canvas {
|
|||||||
height: 20px;
|
height: 20px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
.overlay {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
animation: timerAnimation 15s linear infinite;
|
||||||
|
transition-duration: 15s;
|
||||||
|
}
|
||||||
#root {
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
grid-template-columns: 230px 230px;
|
||||||
|
grid-template-rows: 50px 250px 250px 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-container {
|
||||||
|
place-self: center;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
grid-row: 2 / span 2;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user