Compare commits

..

15 Commits

Author SHA1 Message Date
2cc97c8de8 Ajout de la fonctionnalité de réduction de card lorsque l'on clique sur une des trois card dans le gamecontrol 2024-04-12 21:16:12 +02:00
3826a067e2 Décalage du boutton Debugger 2024-04-05 16:03:49 +02:00
76383c1a3d Ajustement du menu router pour cacher le debugger, il est désormais accessible depuis la page paramètre, onglet MQTT 2024-04-05 16:01:13 +02:00
8b012757f3 Ajustement de la section Son pourque les emplacements soient plus optimisés 2024-04-05 15:48:39 +02:00
0dea30e8a6 Modification du titre Brain Blast dans la barre de menu, désormais elle ne s'affiche que lorsque l'on ne se trouve pas sur la page d'accueil (sinon cela fait redondance avec le logo principal) 2024-04-05 15:14:28 +02:00
da4daae323 Suppression de la page About 2024-04-05 15:11:51 +02:00
ef4838bde1 Modification de l'écart de la carte solution par rapport aux autres 2024-04-05 15:03:58 +02:00
1edb73bf5f Création de la carte timer dans le GameStatus 2024-04-05 15:00:41 +02:00
5a983f2c7e Transformation des scores en card 2024-04-05 14:33:54 +02:00
96b7b1cbd7 Ajout de la card Timer pour créer un chronomètre de jeu 2024-04-05 14:29:08 +02:00
080601b792 Ajustement du placement des score, tout est bien aligné et centré 2024-04-05 14:12:22 +02:00
c3b86cb68b Modification des données affichée dans la gestion des scores, ajout de la notion Total et Manche (affichage de la manche courante et du score total) 2024-04-01 17:40:18 +02:00
44ce39bf3f Merge remote-tracking branch 'origin/soundboard-server' into DataWorking 2024-04-01 16:30:40 +02:00
068e24ba60 add mqtt soundplayer 2024-04-01 14:23:37 +00:00
995cca83ae Modification des données affichée dans la gestion des scores en vu d'une migration vers du dialog via WebSocket entre le serveur backend et le frontend 2024-04-01 15:03:27 +02:00
20 changed files with 775 additions and 136 deletions

238
ui/package-lock.json generated
View File

@ -10,14 +10,17 @@
"dependencies": {
"@mdi/font": "^7.4.47",
"mqtt": "^5.3.5",
"ping": "^0.4.4",
"roboto-fontface": "^0.10.0",
"vue": "^3.4.19",
"vue-router": "^4.2.5"
"vue-router": "^4.2.5",
"vuex": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/eslint-config-prettier": "^8.0.0",
"concurrently": "^8.2.2",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.3",
@ -1171,6 +1174,20 @@
"node": ">= 6"
}
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1227,6 +1244,48 @@
"node": ">= 6"
}
},
"node_modules/concurrently": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz",
"integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
"date-fns": "^2.30.0",
"lodash": "^4.17.21",
"rxjs": "^7.8.1",
"shell-quote": "^1.8.1",
"spawn-command": "0.0.2",
"supports-color": "^8.1.1",
"tree-kill": "^1.2.2",
"yargs": "^17.7.2"
},
"bin": {
"conc": "dist/bin/concurrently.js",
"concurrently": "dist/bin/concurrently.js"
},
"engines": {
"node": "^14.13.0 || >=16.0.0"
},
"funding": {
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
}
},
"node_modules/concurrently/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -1258,6 +1317,22 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1292,6 +1367,12 @@
"node": ">=6.0.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@ -1341,6 +1422,15 @@
"@esbuild/win32-x64": "0.19.12"
}
},
"node_modules/escalade": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -1732,6 +1822,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -1888,6 +1987,15 @@
"node": ">=0.10.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@ -2297,6 +2405,14 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/ping": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/ping/-/ping-0.4.4.tgz",
"integrity": "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/postcss": {
"version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
@ -2452,6 +2568,15 @@
"resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
"integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@ -2551,6 +2676,15 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@ -2592,6 +2726,15 @@
"node": ">=8"
}
},
"node_modules/shell-quote": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
"integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -2600,6 +2743,12 @@
"node": ">=0.10.0"
}
},
"node_modules/spawn-command": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz",
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
"dev": true
},
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
@ -2635,6 +2784,20 @@
}
]
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@ -2705,6 +2868,15 @@
"node": ">=8.0"
}
},
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true,
"bin": {
"tree-kill": "cli.js"
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@ -2980,6 +3152,17 @@
}
}
},
"node_modules/vuex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
"integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==",
"dependencies": {
"@vue/devtools-api": "^6.0.0-beta.11"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
@ -3041,6 +3224,23 @@
"tslib": "^2.6.2"
}
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@ -3076,12 +3276,48 @@
"node": ">=12"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@ -1,10 +1,11 @@
{
"name": "brain-blast",
"version": "0.0.0",
"private": true,
"private": false,
"type": "module",
"scripts": {
"dev": "vite",
"dev-complete": "concurrently \"vite\" \"node ./src/services/buzzerWatcher.js\"",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
@ -13,14 +14,17 @@
"dependencies": {
"@mdi/font": "^7.4.47",
"mqtt": "^5.3.5",
"ping": "^0.4.4",
"roboto-fontface": "^0.10.0",
"vue": "^3.4.19",
"vue-router": "^4.2.5"
"vue-router": "^4.2.5",
"vuex": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/eslint-config-prettier": "^8.0.0",
"concurrently": "^8.2.2",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.3",

BIN
ui/src/assets/design.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

View File

@ -1,7 +1,7 @@
<template>
<v-app-bar :elevation="5" height="50">
<RouterMenu />
<v-app-bar-title>Brain Blast</v-app-bar-title>
<v-app-bar-title v-if="$route.name !== 'Accueil'">Brain Blast</v-app-bar-title>
<template v-slot:append>
<v-btn icon @click="toggleTheme">

View File

@ -1,6 +1,6 @@
<template>
<v-card tile outlined class="card">
<v-card-title class="card__title primary">
<v-card tile outlined :class="{ 'card--reduced': isCardReduced }">
<v-card-title class="card__title primary" @click="toggleCardSize">
<v-icon left class="white--text pr-5 pl-2" size="40">mdi-camera-control</v-icon>
Contrôles
</v-card-title>
@ -33,4 +33,22 @@
<script setup>
import MqttButton from './MqttButton.vue';
import { ref } from 'vue';
// Variable pour contrôler l'état de la carte
const isCardReduced = ref(false);
// Méthode pour basculer l'état de la carte
function toggleCardSize() {
isCardReduced.value = !isCardReduced.value;
}
</script>
<style>
.card--reduced {
height: 56px; /* Réglez la hauteur réduite selon vos besoins */
width: 170px;
overflow: hidden;
transition: height 0.3s ease-in-out;
}
</style>

View File

@ -0,0 +1,161 @@
<template>
<div class="label-pos">
<v-label class="labelTitle-style pb-4">Scores</v-label>
</div>
<!-- Équipes Rouges et Bleues côte à côte -->
<v-row no-gutters class="scorebox-pos">
<!-- Équipe Rouge -->
<v-col cols="6"> <!-- Colonnes de taille 6 pour chaque équipe -->
<v-row no-gutters>
<v-col class="scorediv-style-red">
<div>
<v-label class="labelRoundScore-style pt-3">Manche</v-label>
<div>
<v-label class="labelRoundScore-style">{{ RedRoundScore }}</v-label>
</div>
</div>
<v-divider color="background"/>
<div>
<v-label class="labelTotalScore-style pt-3">Total</v-label>
<div>
<v-label class="labelTotalScore-style pb-3">{{ RedTotalScore }}</v-label>
</div>
</div>
</v-col>
</v-row>
</v-col>
<!-- Équipe Bleue -->
<v-col cols="6">
<v-row no-gutters>
<v-col class="scorediv-style-blue">
<div>
<v-label class="labelRoundScore-style pt-3">Manche</v-label>
<div>
<v-label class="labelRoundScore-style">{{ BlueRoundScore }}</v-label>
</div>
</div>
<v-divider color="background"/>
<div>
<v-label class="labelTotalScore-style pt-3">Total</v-label>
<div>
<v-label class="labelTotalScore-style pb-3">{{ BlueTotalScore }}</v-label>
</div>
</div>
</v-col>
</v-row>
</v-col>
</v-row>
<!-- Équipes Oranges et Vertes côte à côte -->
<v-row no-gutters class="scorebox-pos">
<!-- Équipe Orange -->
<v-col cols="6">
<v-row no-gutters>
<v-col class="scorediv-style-orange">
<div>
<v-label class="labelRoundScore-style pt-3">Manche</v-label>
<div>
<v-label class="labelRoundScore-style">{{ OrangeRoundScore }}</v-label>
</div>
</div>
<v-divider color="background"/>
<div>
<v-label class="labelTotalScore-style pt-3">Total</v-label>
<div>
<v-label class="labelTotalScore-style pb-3">{{ OrangeTotalScore }}</v-label>
</div>
</div>
</v-col>
</v-row>
</v-col>
<!-- Équipe Verte -->
<v-col cols="6">
<v-row no-gutters>
<v-col class="scorediv-style-green">
<div>
<v-label class="labelRoundScore-style pt-3">Manche</v-label>
<div>
<v-label class="labelRoundScore-style">{{ GreenRoundScore }}</v-label>
</div>
</div>
<v-divider color="background"/>
<div>
<v-label class="labelTotalScore-style pt-3">Total</v-label>
<div>
<v-label class="labelTotalScore-style pb-3">{{ GreenTotalScore }}</v-label>
</div>
</div>
</v-col>
</v-row>
</v-col>
</v-row>
</template>
<script setup>
import { ref } from 'vue'; // Import des fonctions de Vue 3
import variables from '@/variables.js';
// Déclaration des variables locales pour les scores
const RedTotalScore = ref(variables.RedTotalScore);
const BlueTotalScore = ref(variables.BlueTotalScore);
const OrangeTotalScore = ref(variables.OrangeTotalScore);
const GreenTotalScore = ref(variables.GreenTotalScore);
const RedRoundScore = ref(variables.RedRoundScore);
const BlueRoundScore = ref(variables.BlueRoundScore);
const OrangeRoundScore = ref(variables.OrangeRoundScore);
const GreenRoundScore = ref(variables.GreenRoundScore);
</script>
<style>
.label-pos {
padding-top: 15px;
text-align: center;
}
.labelTitle-style {
font-size: 20px !important;
font-weight: 500;
color: #e91e1e !important;
opacity: 90% !important;
}
.labelRoundScore-style {
opacity: 100% !important;
font-size: 25px !important;
font-weight: 500;
}
.labelTotalScore-style {
opacity: 100% !important;
font-size: 15px !important;
font-weight: 500;
}
.button-pos {
padding-top: 10px;
padding-bottom: 15px;
}
.scorebox-pos {
text-align: center;
}
.scorediv-style-red {
background-color: #d42828 !important;
padding: 15px;
border-top-left-radius: 10%;
}
.scorediv-style-orange {
background-color: #d48f28 !important;
padding: 15px;
border-bottom-left-radius: 10%;
}
.scorediv-style-blue {
background-color: #2867d4 !important;
padding: 15px;
border-top-right-radius: 10%;
}
.scorediv-style-green {
background-color: #28d42e !important;
padding: 15px;
border-bottom-right-radius: 10%;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<v-card tile outlined class="card">
<v-card-title class="card__title feedback">
<v-card tile outlined :class="{ 'card--reduced': isCardReduced }">
<v-card-title class="card__title feedback" @click="toggleCardSize">
<v-icon left class="white--text pr-5 pl-2" size="40">mdi-play-network-outline</v-icon>
Solution
</v-card-title>
@ -27,4 +27,22 @@
display: block; /* Pour éviter l'espace réservé pour les images */
}
}
.card--reduced {
height: 56px; /* Réglez la hauteur réduite selon vos besoins */
width: 160px;
overflow: hidden;
transition: height 0.6s ease-in-out;
}
</style>
<script setup>
import { ref } from 'vue';
// Variable pour contrôler l'état de la carte
const isCardReduced = ref(false);
// Méthode pour basculer l'état de la carte
function toggleCardSize() {
isCardReduced.value = !isCardReduced.value;
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<v-card tile outlined class="card">
<v-card-title class="card__title primary">
<v-card tile outlined :class="{ 'card--reduced': isCardReduced }">
<v-card-title class="card__title primary" @click="toggleCardSize">
<v-icon left class="white--text pr-5 pl-2" size="40">mdi-music-box-multiple</v-icon>
Soundboard
</v-card-title>
@ -40,4 +40,22 @@
<script setup>
import MqttButton from './MqttButton.vue';
import { ref } from 'vue';
// Variable pour contrôler l'état de la carte
const isCardReduced = ref(false);
// Méthode pour basculer l'état de la carte
function toggleCardSize() {
isCardReduced.value = !isCardReduced.value;
}
</script>
<style scoped>
.card--reduced {
height: 56px; /* Réglez la hauteur réduite selon vos besoins */
width: 190px;
overflow: hidden;
transition: height 0.3s ease-in-out;
}
</style>

View File

@ -0,0 +1,118 @@
<template>
<div class="container">
<div class="timer">
<v-label color="primary" class="labelTime-style" >{{ formatTime }}</v-label>
</div>
<v-row no-gutters justify="space-around" >
<v-btn class="buttons" color="primary" icon="mdi-play" @click="startTimer"></v-btn>
<v-btn color="primary" icon="mdi-pause" @click="pauseTimer"></v-btn>
<v-btn color="primary" icon="mdi-restart" @click="resetTimer"></v-btn>
</v-row>
</div>
</template>
<script setup>
import { ref, computed, onBeforeUnmount } from 'vue';
const timerActive = ref(false);
const startTime = ref(null);
const currentTime = ref(null);
const elapsedTime = ref(0);
const formatTime = computed(() => {
let seconds = Math.floor(elapsedTime.value / 1000);
let minutes = Math.floor(seconds / 60);
let hours = Math.floor(minutes / 60);
seconds = seconds % 60;
minutes = minutes % 60;
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
});
const pad = (number) => {
return (number < 10 ? "0" : "") + number;
};
const startTimer = () => {
if (!timerActive.value) {
timerActive.value = true;
startTime.value = Date.now() - elapsedTime.value;
updateTimer();
}
};
const pauseTimer = () => {
if (timerActive.value) {
timerActive.value = false;
clearInterval(currentTime.value);
}
};
const resetTimer = () => {
elapsedTime.value = 0;
timerActive.value = false;
clearInterval(currentTime.value);
};
const updateTimer = () => {
currentTime.value = setInterval(() => {
elapsedTime.value = Date.now() - startTime.value;
}, 1000);
};
onBeforeUnmount(() => {
clearInterval(currentTime.value);
});
</script>
<script>
const startTimer = () => {
if (!timerActive.value) {
timerActive.value = true;
startTime.value = Date.now() - elapsedTime.value;
updateTimer();
}
};
const pauseTimer = () => {
if (timerActive.value) {
timerActive.value = false;
clearInterval(currentTime.value);
}
};
const resetTimer = () => {
elapsedTime.value = 0;
timerActive.value = false;
clearInterval(currentTime.value);
};
export { startTimer, pauseTimer, resetTimer };
</script>
<style>
.container {
text-align: center;
margin-top: auto; /* Place le container en bas de son parent */
margin-bottom: 1px; /* Marge en bas pour un espacement */
position: fixed; /* Le positionne de manière fixe */
left: 0;
right: 0;
bottom: 0;
padding: 20px;
}
.timer {
margin-bottom: 15px;
}
.labelTime-style {
font-size: 30px !important;
font-weight: 500;
color: #e91e1e !important;
opacity: 90% !important;
}
.buttons{
background-color: rgb(255, 255, 255);
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<v-navigation-drawer width="250">
<v-navigation-drawer width="250"> <!-- Augmenter la largeur pour deux équipes côte à côte -->
<div class="label-pos">
<v-label class="labelTitle-style">Buzzer connectés</v-label>
</div>
@ -12,84 +12,34 @@
</v-row>
<v-divider :thickness="2" class="border-opacity-100" color="primary"/>
<div class="label-pos">
<v-label class="labelTitle-style pb-7">Scores</v-label>
</div>
<div>
<v-row no-gutters justify="space-around" class="scorebox-1-pos">
<v-row>
<v-col class="align-start scorediv-style-red pr-1">
<v-label class="labelScore-style">{{ localStorageVars.RedScore }}</v-label>
</v-col>
<v-col class="align-start scorediv-style-blue pl-1">
<v-label class="labelScore-style">{{ localStorageVars.BlueScore }}</v-label>
</v-col>
</v-row>
</v-row>
</div>
<div>
<v-row no-gutters justify="space-around" class="scorebox-2-pos mb-0">
<v-row>
<v-col class="align-start scorediv-style-orange pr-1">
<v-label class="labelScore-style">{{ localStorageVars.OrangeScore }}</v-label>
</v-col>
<v-col class="align-start scorediv-style-green pl-1">
<v-label class="labelScore-style">{{ localStorageVars.GreenScore }}</v-label>
</v-col>
</v-row>
</v-row>
</div>
<CardScore/>
<CardTimer/>
</v-navigation-drawer>
</template>
<script setup>
import { localStorageVars } from '@/variables.js';
localStorage.setItem('RedScore', 10);
localStorage.setItem('BlueScore', 11);
localStorage.setItem('OrangeScore', 12);
localStorage.setItem('GreenScore', 13);
import CardTimer from '@/components/CardTimer.vue'
import CardScore from '@/components/CardScore.vue'
import { ref } from 'vue'; // Import des fonctions de Vue 3
import variables from '@/variables.js';
</script>
<style>
.label-pos{
.label-pos {
padding-top: 15px;
text-align: center;
}
.labelTitle-style{
.labelTitle-style {
font-size: 20px !important;
font-weight: 500;
color: #e91e1e !important;
opacity: 90% !important;
}
.labelScore-style{
opacity: 100% !important;
}
.button-pos{
.button-pos {
padding-top: 10px;
padding-bottom: 15px;
}
.scorebox-1-pos{
padding-bottom: 15px;
text-align: center;
margin:auto;
}
.scorebox-2-pos{
padding-top: 9px;
text-align: center;
margin:auto;
}
.scorediv-style-red{
background-color: #d42828 !important;
}
.scorediv-style-orange{
background-color: #d48f28 !important;
}
.scorediv-style-blue{
background-color: #2867d4 !important;
}
.scorediv-style-green{
background-color: #28d42e !important;
}
</style>

View File

@ -2,23 +2,28 @@
<v-app-bar-nav-icon v-on:click="menu = !menu"></v-app-bar-nav-icon>
<v-menu v-model="menu" class="menu-below-bar">
<v-list>
<v-list-item v-for="route in routes" :key="route.name" :to="route.path">{{ route.name }}</v-list-item>
<v-list-item v-for="route in filteredRoutes" :key="route.name" :to="route.path">{{ route.name }}</v-list-item>
</v-list>
</v-menu>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter()
const routes = router.options.routes
const router = useRouter();
const routes = router.options.routes;
let menu = ref(false)
let menu = ref(false);
// Filtrer les routes pour masquer une route spécifique (par exemple, 'RouteA')
const filteredRoutes = computed(() => {
return routes.filter(route => route.name !== 'Debugger MQTT');
});
</script>
<style scoped>
.menu-below-bar {
.menu-below-bar {
margin-top: 48px; /* La hauteur de la barre d'application */
}
}
</style>

View File

@ -4,5 +4,13 @@
// config.js
export default {
mqttBrokerUrl: 'ws://localhost:9001'
mqttBrokerUrl: 'ws://192.168.1.78:9001',
// Buzzer
redBuzzerIP: '',
blueBuzzerIP: '',
orangeBuzzerIP: '',
greenBuzzerIP: ''
// Light
};

View File

@ -6,17 +6,9 @@ const router = createRouter({
routes: [
{
path: '/',
name: 'Home',
name: 'Accueil',
component: HomeView
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('@/views/AboutView.vue')
},
{
path: '/game/control',
name: 'Game Control (Présentateur)',

View File

@ -38,7 +38,11 @@ const CustomThemeLight = {
error: '#e91e1e',
warning: '#FFC107',
info: '#607D8B',
success: '#4CAF50'
success: '#4CAF50',
BuzzerBlue: '#2867d4',
BuzzerOrange: '#d48f28',
BuzzerRed: '#d42828',
BuzzerGreen: '#28d42e',
}
}

View File

@ -0,0 +1,66 @@
// index.js
import Vue from 'vue';
import Vuex from 'vuex';
import ping from 'ping';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
buzzerRedState: '',
buzzerBlueState: '',
buzzerOrangeState: '',
buzzerGreenState: ''
},
mutations: {
setBuzzerRedState(state, newState) {
state.buzzerRedState = newState;
},
setBuzzerBlueState(state, newState) {
state.buzzerBlueState = newState;
},
setBuzzerOrangeState(state, newState) {
state.buzzerOrangeState = newState;
},
setBuzzerGreenState(state, newState) {
state.buzzerGreenState = newState;
}
},
actions: {
updateBuzzerStates({ commit }, { index, newState }) {
switch (index) {
case 0:
commit('setBuzzerRedState', newState);
break;
case 1:
commit('setBuzzerBlueState', newState);
break;
case 2:
commit('setBuzzerOrangeState', newState);
break;
case 3:
commit('setBuzzerGreenState', newState);
break;
default:
console.error('Index de buzzer invalide:', index);
}
}
}
});
const hosts = ['192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.4'];
async function pingHosts() {
hosts.forEach(async (host, index) => {
try {
const res = await ping.promise.probe(host);
store.dispatch('updateBuzzerStates', { index, newState: res.alive ? 'ON' : 'OFF' });
} catch (error) {
console.error(`Erreur lors du ping de ${host}:`, error.message);
}
});
}
pingHosts();
module.exports = store;

View File

@ -1,8 +1,32 @@
export default {
// Gestion des score et des Buzzers
// Scores totaux
RedTotalScore: 11,
BlueTotalScore: 22,
GreenTotalScore: 33,
OrangeTotalScore: 44,
// Score de la manche courante
RedRoundScore: 1,
BlueRoundScore: 2,
OrangeRoundScore: 3,
GreenRoundScore: 4,
//Etat des buzzer
BuzzerRed: false,
BuzzerBlue: false,
BuzzerOrange: false,
BuzzerGreen: false,
// Ajoutez d'autres variables globales ici
};
// Variables localStorage
export const localStorageVars = {
// Exemple de variable localStorage
RedScore: localStorage.getItem('RedScore') || '',
BlueScore: localStorage.getItem('BlueScore') || '',
OrangeScore: localStorage.getItem('OrangeScore') || '',
GreenScore: localStorage.getItem('GreenScore') || '',
RedScorelocal: localStorage.getItem('RedScore') || '',
BlueScorelocal: localStorage.getItem('BlueScore') || '',
OrangeScorelocal: localStorage.getItem('OrangeScore') || '',
GreenScorelocal: localStorage.getItem('GreenScore') || '',
};

View File

@ -1,24 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
<hr/>
<p>
Exemple d'une page
</p><p>
Ou il y a un scroll
</p><p>
Pour mettre en valeur leu footer fixe en bas de page
</p><p>
Cette page n'a aucun interet et pourra etre supprimée
</p>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
align-items: center;
}
}
</style>

View File

@ -9,13 +9,13 @@
</v-col>
</v-row>
</v-container>
<v-container>
<v-row no-gutters>
<v-row no-gutters class="pr-4 pl-4">
<v-col>
<card-solution />
</v-col>
</v-row>
</v-container>
</template>
<script setup>

View File

@ -0,0 +1,3 @@
<template>
</template>

View File

@ -1,23 +1,27 @@
<template>
<h1 class="title mb-4 ml-5 mt-5">Paramètres</h1>
<v-label class="title-style-1">Paramètres</v-label>
<v-divider :thickness="2" class="border-opacity-100" color="primary"/>
<h2 class="title ml-10 mb-5 mt-5">Son</h2>
<div style="display: flex; align-items: center;">
<v-switch label="Activer le son intégré" v-model="EmbeddedSound" class="ml-15" color="primary"/>
<div style="width: 250px; margin-left: 16px;">
<v-slider class="ml-15" :disabled="EmbeddedSound === false" v-model="EmbeddedSoundVolume" color="primary"/>
<v-label class="title-style-2">Son</v-label>
<div class="mutltiple-per-line">
<v-switch hide-details label="Activer le son intégré" v-model="EmbeddedSound" class="ml-15" color="primary"/>
<div>
<v-slider hide-details class="v-slider-style ml-15" :disabled="EmbeddedSound === false" v-model="EmbeddedSoundVolume" color="primary"/>
</div>
</div>
<v-switch label="Activer le son MQTT" v-model="MQTTSound" class="ml-15" color="primary"/>
<v-divider />
<h2 class="title ml-10 mb-5 mt-5">Affichage</h2>
<v-label class="title-style-2">Affichage</v-label>
<v-switch label="Activer l'affichage des sattelites" v-model="SattelitesDisplay" class="ml-15" color="primary"/>
<v-divider />
<h2 class="title ml-10 mb-5 mt-5">MQTT</h2>
<div style="display: flex; align-items: center;">
<v-label class="title-style-2">MQTT</v-label>
<div class="mutltiple-per-line">
<v-icon v-model="MQTTBrokerState" class="ml-15 mb-5" color="error" icon="record">mdi-record</v-icon>
<v-label class="ml-2 mb-10 mt-5">Etat du serveur MQTT</v-label>
<v-btn class="ml-10 mb-5" color="primary" @click="goToDebugRoute">Debugger</v-btn>
</div>
<v-divider />
</template>
@ -25,12 +29,18 @@
<script setup>
import { ref, onMounted, watch } from 'vue';
import { useRouter } from 'vue-router';
const EmbeddedSound = ref(false); // Définition d'une référence pour la case à cocher. Initialement décochée.
const EmbeddedSoundVolume = ref(50); // Définition d'une référence pour la case à cocher. Initialement décochée.
const MQTTSound = ref(false); // Définition d'une référence pour la case à cocher. Initialement décochée.
const MQTTBrokerState = ref(false); // Définition d'une référence pour la case à cocher. Initialement décochée.
const SattelitesDisplay = ref(false);
const router = useRouter();
const goToDebugRoute = () => {
router.push({ name: 'Debugger MQTT' }); // Redirige vers la route nommée 'debugger'
};
onMounted(() => {
if (localStorage.getItem('EmbeddedSound')) {
@ -69,3 +79,31 @@
});
</script>
<style>
.title-style-1{
margin-top: 20px;
margin-bottom: 16px;
margin-left: 20px;
font-size: 30px;
opacity: 100%;
font-weight: 500;
}
.title-style-2{
margin-top: 20px;
margin-bottom: 10px;
margin-left: 40px;
font-size: 25px;
opacity: 100%;
font-weight: 500;
}
.mutltiple-per-line{
display: flex;
align-items: center;
}
.v-slider-style{
width: 250px;
margin-left: 16px;
padding-top: px;
}
</style>