mirror of
https://github.com/anatolykopyl/vk-bingo.git
synced 2026-03-26 21:04:26 +00:00
Redesign and fix dupe events
This commit is contained in:
@@ -3,6 +3,7 @@ import session from 'express-session';
|
|||||||
import mongodb from 'mongodb';
|
import mongodb from 'mongodb';
|
||||||
import MongoStore from 'connect-mongo';
|
import MongoStore from 'connect-mongo';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
|
import crypto from 'crypto'
|
||||||
import { createNanoEvents } from 'nanoevents';
|
import { createNanoEvents } from 'nanoevents';
|
||||||
|
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
@@ -103,7 +104,6 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true });
|
|||||||
}
|
}
|
||||||
|
|
||||||
let players = {}
|
let players = {}
|
||||||
let oldPlayers = {}
|
|
||||||
let score = {}
|
let score = {}
|
||||||
let card = await drawCard()
|
let card = await drawCard()
|
||||||
let oldCard = null;
|
let oldCard = null;
|
||||||
@@ -257,6 +257,8 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true });
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/stream', async (req, res) => {
|
app.get('/api/stream', async (req, res) => {
|
||||||
|
const id = crypto.randomUUID()
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
@@ -278,6 +280,7 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true });
|
|||||||
players,
|
players,
|
||||||
selected
|
selected
|
||||||
}
|
}
|
||||||
|
|
||||||
res.write(`data: ${JSON.stringify(data)}\nevent: answer\n\n`);
|
res.write(`data: ${JSON.stringify(data)}\nevent: answer\n\n`);
|
||||||
|
|
||||||
answers += 1
|
answers += 1
|
||||||
@@ -295,11 +298,12 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true });
|
|||||||
answers = 0
|
answers = 0
|
||||||
oldCard = { ...card }
|
oldCard = { ...card }
|
||||||
card = await drawCard()
|
card = await drawCard()
|
||||||
emitter.emit('allDone');
|
|
||||||
|
emitter.emit(`allDone-${id}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('allDone', () => {
|
const unbindAllDone = emitter.on(`allDone-${id}`, () => {
|
||||||
const data = {
|
const data = {
|
||||||
correctAnswer: oldCard.name,
|
correctAnswer: oldCard.name,
|
||||||
score
|
score
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--clr-bg: #ffd537;
|
--clr-bg: #ffd537;
|
||||||
--clr-accent: #37ffac;
|
--clr-accent: #37ffac;
|
||||||
|
--clr-text: #141414;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -35,16 +36,17 @@ body {
|
|||||||
background-color: var(--clr-bg);
|
background-color: var(--clr-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input, button {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
font-family: "Pangram Sans Rounded", Avenir, Helvetica, Arial, sans-serif;
|
font-family: "Pangram Sans Rounded", Avenir, Helvetica, Arial, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: black;
|
color: var(--clr-text);
|
||||||
margin-top: 60px;
|
min-height: 100vh;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
|
||||||
#game {
|
|
||||||
margin-bottom: 100px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
$resulting-shadow: null;
|
$resulting-shadow: null;
|
||||||
|
|
||||||
@for $i from 1 through $distance {
|
@for $i from 1 through $distance {
|
||||||
$resulting-shadow: $resulting-shadow, #{$i}px #{$i}px 0 black;
|
$resulting-shadow: $resulting-shadow, #{$i}px #{$i}px 0 var(--clr-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
box-shadow: $resulting-shadow;
|
box-shadow: $resulting-shadow;
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ function endGame() {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.end {
|
.end {
|
||||||
position: fixed;
|
// position: fixed;
|
||||||
bottom: 8px;
|
// bottom: 8px;
|
||||||
left: 50%;
|
// left: 50%;
|
||||||
transform: translateX(-50%);
|
// transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.endButton {
|
.endButton {
|
||||||
@@ -33,7 +33,7 @@ function endGame() {
|
|||||||
border: none;
|
border: none;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-bottom: 1px dotted black;
|
border-bottom: 1px dotted var(--clr-text);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<h1>Флекспатруль мультиплеер</h1>
|
<h1 class="header">Флекспатруль мультиплеер</h1>
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div
|
<div
|
||||||
@@ -12,16 +12,14 @@
|
|||||||
>
|
>
|
||||||
<h2>Кто скинул этот мем?</h2>
|
<h2>Кто скинул этот мем?</h2>
|
||||||
<div class="interactive">
|
<div class="interactive">
|
||||||
<transition name="fade-answers">
|
<transition name="fade-answers" mode="out-in">
|
||||||
<List
|
<List
|
||||||
v-if="!showResult"
|
v-if="!showResult"
|
||||||
:options="options"
|
:options="options"
|
||||||
@selectedAnswer="selectAnswer"
|
@selectedAnswer="selectAnswer"
|
||||||
/>
|
/>
|
||||||
</transition>
|
|
||||||
<transition name="spin-result">
|
|
||||||
<Result
|
<Result
|
||||||
v-if="showResult"
|
v-else
|
||||||
:selectedName="selectedAnswer"
|
:selectedName="selectedAnswer"
|
||||||
:correct="correctAnswer"
|
:correct="correctAnswer"
|
||||||
/>
|
/>
|
||||||
@@ -97,19 +95,32 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.header {
|
||||||
|
padding: 60px;
|
||||||
|
margin: auto;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding-bottom: 200px;
|
position: relative;
|
||||||
|
min-height: calc(100vh - 162px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
margin: auto;
|
margin: 0 auto;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meme {
|
.meme {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 32px;
|
border-radius: 32px;
|
||||||
border: 3px solid black;
|
border: 3px solid var(--clr-text);
|
||||||
@include filled-shadow(16);
|
@include filled-shadow(16);
|
||||||
transform: translateX(-8px);
|
transform: translateX(-8px);
|
||||||
}
|
}
|
||||||
@@ -120,11 +131,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
.interactive {
|
.interactive {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
> * {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-answers-leave-active {
|
.fade-answers-leave-active {
|
||||||
@@ -135,14 +141,6 @@ onMounted(async () => {
|
|||||||
transform: scale(0.3);
|
transform: scale(0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.spin-result-enter-active {
|
|
||||||
transition: all 2s ease;
|
|
||||||
}
|
|
||||||
.spin-result-enter-from {
|
|
||||||
transform: scale(0.2);
|
|
||||||
transform: rotateY(120deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
.loader {
|
||||||
margin-top: 100px;
|
margin-top: 100px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ export default {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.result {
|
.result {
|
||||||
padding: 30px 40px;
|
padding: 30px 40px;
|
||||||
border-radius: 8px;
|
border-radius: 32px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.correct {
|
.correct {
|
||||||
color: black;
|
color: var(--clr-text);
|
||||||
background-color: var(--clr-accent);
|
background-color: var(--clr-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<h1>Флекспатруль мультиплеер</h1>
|
|
||||||
|
|
||||||
<div class="authCard">
|
<div class="authCard">
|
||||||
<h1>Авторизация:</h1>
|
<h1>Авторизация:</h1>
|
||||||
|
|
||||||
@@ -9,21 +7,25 @@
|
|||||||
<input
|
<input
|
||||||
placeholder="Ответ"
|
placeholder="Ответ"
|
||||||
v-model="answer"
|
v-model="answer"
|
||||||
|
class="input"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-if="mode === 'player'"
|
v-if="mode === 'player'"
|
||||||
placeholder="Ваше имя"
|
placeholder="Ваше имя"
|
||||||
v-model="username"
|
v-model="username"
|
||||||
|
class="input"
|
||||||
>
|
>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="mode === 'player'"
|
v-if="mode === 'player'"
|
||||||
|
class="login"
|
||||||
@click="loginPlayer"
|
@click="loginPlayer"
|
||||||
>
|
>
|
||||||
Войти как игрок
|
Войти как игрок
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
|
class="login"
|
||||||
@click="loginScreen"
|
@click="loginScreen"
|
||||||
>
|
>
|
||||||
Войти как большой экран
|
Войти как большой экран
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
@click="switchMode"
|
@click="switchMode"
|
||||||
class="secondary"
|
class="switchMode"
|
||||||
>
|
>
|
||||||
Я не {{ mode === 'player' ? 'игрок' : 'большой экран' }}!
|
Я не {{ mode === 'player' ? 'игрок' : 'большой экран' }}!
|
||||||
</button>
|
</button>
|
||||||
@@ -60,6 +62,10 @@ function switchMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loginPlayer() {
|
async function loginPlayer() {
|
||||||
|
if (!answer.value || !username.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
store.username = username.value
|
store.username = username.value
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
@@ -83,7 +89,7 @@ async function loginScreen() {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
.auth {
|
.auth {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
@@ -92,43 +98,68 @@ async function loginScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.authCard {
|
.authCard {
|
||||||
background-color: #121212;
|
position: fixed;
|
||||||
color: white;
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: var(--clr-text);
|
||||||
|
color: var(--clr-text);
|
||||||
width: 400px;
|
width: 400px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border-radius: 18px;
|
border-radius: 32px;
|
||||||
padding: 40px 10px;
|
padding: 40px 40px;
|
||||||
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.6);
|
box-sizing: border-box;
|
||||||
|
background: white;
|
||||||
|
border: 3px solid var(--clr-text);
|
||||||
|
@include filled-shadow(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
.input {
|
||||||
font-size: 1em;
|
font-size: 16px;
|
||||||
text-align: center;
|
padding: 16px;
|
||||||
padding: 5px 8px;
|
border: 2px solid var(--clr-text);
|
||||||
border-radius: 6px;
|
width: 100%;
|
||||||
border: none;
|
box-sizing: border-box;
|
||||||
width: 20ch;
|
@include filled-shadow(4);
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.login {
|
||||||
color: white;
|
color: var(--clr-text);
|
||||||
font-size: 1em;
|
font-size: 16px;
|
||||||
box-sizing: content-box;
|
box-sizing: border-box;
|
||||||
background-color: #5a5a5a;
|
background-color: var(--clr-bg);
|
||||||
border-radius: 6px;
|
|
||||||
border: none;
|
border: none;
|
||||||
width: 20ch;
|
width: 100%;
|
||||||
padding: 5px 8px;
|
padding: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border: 2px solid var(--clr-text);
|
||||||
|
@include filled-shadow(4);
|
||||||
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.secondary {
|
.switchMode {
|
||||||
background: #919191;
|
position: absolute;
|
||||||
|
color: var(--clr-text);
|
||||||
|
background: var(--clr-accent);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
border-radius: 100px;
|
||||||
|
border: 2px solid var(--clr-text);
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translate(-50%, 50%);
|
||||||
|
cursor: pointer;
|
||||||
|
@include filled-shadow(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 520px) {
|
@media only screen and (max-width: 520px) {
|
||||||
div {
|
.authCard {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 40px 0;
|
padding: 40px 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const position = reactive({
|
|||||||
border-radius: 32px;
|
border-radius: 32px;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
border: 3px solid black;
|
border: 3px solid var(--clr-text);
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ onMounted(() => {
|
|||||||
padding: 64px;
|
padding: 64px;
|
||||||
background: var(--clr-bg);
|
background: var(--clr-bg);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: black;
|
color: var(--clr-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
@@ -158,7 +158,8 @@ onMounted(() => {
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
border: 3px solid black;
|
background: var(--clr-text);
|
||||||
|
border: 3px solid var(--clr-text);
|
||||||
@include filled-shadow(16);
|
@include filled-shadow(16);
|
||||||
border-radius: 64px;
|
border-radius: 64px;
|
||||||
animation-name: rock;
|
animation-name: rock;
|
||||||
@@ -187,7 +188,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.users.-unanwsered {
|
.users.-unanwsered {
|
||||||
border-right: 1px dashed black;
|
border-right: 1px dashed var(--clr-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user.-correct {
|
.user.-correct {
|
||||||
|
|||||||
Reference in New Issue
Block a user