step: Working MQTT websocket connection, docker deploy script
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
docker build -t kingArthurApp:latest .
|
||||
docker save kingArthurApp:latest | gzip > kingArthurApp.tar.gz
|
||||
scp kingArthurApp.tar.gz youruser@your_server_ip:~/
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Build stage
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Serve stage
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
Generated
+519
-3
@@ -7,11 +7,23 @@
|
||||
"": {
|
||||
"name": "king-arthur",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"mqtt": "^5.15.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~6.0.2",
|
||||
"vite": "^8.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
@@ -368,6 +380,171 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz",
|
||||
"integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/readable-stream": {
|
||||
"version": "4.0.23",
|
||||
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz",
|
||||
"integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "6.1.6",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz",
|
||||
"integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^4.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/broker-factory": {
|
||||
"version": "3.1.14",
|
||||
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz",
|
||||
"integrity": "sha512-L45k5HMbPIrMid0nTOZ/UPXG/c0aRuQKVrSDFIb1zOkvfiyHgYmIjc3cSiN1KwQIvRDOtKE0tfb3I9EZ3CmpQQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"fast-unique-numbers": "^9.0.27",
|
||||
"tslib": "^2.8.1",
|
||||
"worker-factory": "^7.0.49"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commist": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
|
||||
"integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
|
||||
"engines": [
|
||||
"node >= 6.0"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.0.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
@@ -378,6 +555,37 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-unique-numbers": {
|
||||
"version": "9.0.27",
|
||||
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.27.tgz",
|
||||
"integrity": "sha512-nDA9ADeINN8SA2u2wCtU+siWFTTDqQR37XvgPIDDmboWQeExz7X0mImxuaN+kJddliIqy2FpVRmnvRZ+j8i1/A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
@@ -411,6 +619,57 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/help-me": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
||||
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
||||
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
|
||||
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/js-sdsl"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
@@ -684,6 +943,70 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mqtt": {
|
||||
"version": "5.15.1",
|
||||
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.15.1.tgz",
|
||||
"integrity": "sha512-V1WnkGuJh3ec9QXzy5Iylw8OOBK+Xu1WhxcQ9mMpLThG+/JZIMV1PgLNRgIiqXhZnvnVLsuyxHl5A/3bHHbcAA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^4.0.21",
|
||||
"@types/ws": "^8.18.1",
|
||||
"commist": "^3.2.0",
|
||||
"concat-stream": "^2.0.0",
|
||||
"debug": "^4.4.1",
|
||||
"help-me": "^5.0.0",
|
||||
"lru-cache": "^10.4.3",
|
||||
"minimist": "^1.2.8",
|
||||
"mqtt-packet": "^9.0.2",
|
||||
"number-allocator": "^1.0.14",
|
||||
"readable-stream": "^4.7.0",
|
||||
"rfdc": "^1.4.1",
|
||||
"socks": "^2.8.6",
|
||||
"split2": "^4.2.0",
|
||||
"worker-timers": "^8.0.23",
|
||||
"ws": "^8.18.3"
|
||||
},
|
||||
"bin": {
|
||||
"mqtt": "build/bin/mqtt.js",
|
||||
"mqtt_pub": "build/bin/pub.js",
|
||||
"mqtt_sub": "build/bin/sub.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mqtt-packet": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
|
||||
"integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^6.0.8",
|
||||
"debug": "^4.3.4",
|
||||
"process-nextick-args": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
@@ -703,6 +1026,16 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/number-allocator": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
|
||||
"integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"js-sdsl": "4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -752,6 +1085,43 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
|
||||
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"events": "^3.3.0",
|
||||
"process": "^0.11.10",
|
||||
"string_decoder": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.18",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz",
|
||||
@@ -786,6 +1156,50 @@
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz",
|
||||
"integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ip-address": "^10.1.1",
|
||||
"smart-buffer": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -796,6 +1210,24 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.16",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
||||
@@ -817,9 +1249,13 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"optional": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
@@ -835,6 +1271,18 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.19.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
|
||||
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.11.tgz",
|
||||
@@ -912,6 +1360,74 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/worker-factory": {
|
||||
"version": "7.0.49",
|
||||
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz",
|
||||
"integrity": "sha512-lW7tpgy6aUv2dFsQhv1yv+XFzdkCf/leoKRTGMPVK5/die6RrUjqgJHJf556qO+ZfytNG6wPXc17E8zzsOLUDw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"fast-unique-numbers": "^9.0.27",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/worker-timers": {
|
||||
"version": "8.0.31",
|
||||
"resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.31.tgz",
|
||||
"integrity": "sha512-ngkq5S6JuZyztom8tDgBzorLo9byhBMko/sXfgiUD945AuzKGg1GCgDMCC3NaYkicLpGKXutONM36wEX8UbBCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"tslib": "^2.8.1",
|
||||
"worker-timers-broker": "^8.0.16",
|
||||
"worker-timers-worker": "^9.0.14"
|
||||
}
|
||||
},
|
||||
"node_modules/worker-timers-broker": {
|
||||
"version": "8.0.16",
|
||||
"resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.16.tgz",
|
||||
"integrity": "sha512-JyP3AvUGyPGbBGW7XiUewm2+0pN/aYo1QpVf5kdXAfkDZcN3p7NbWrG6XnyDEpDIvfHk/+LCnOW/NsuiU9riYA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"broker-factory": "^3.1.14",
|
||||
"fast-unique-numbers": "^9.0.27",
|
||||
"tslib": "^2.8.1",
|
||||
"worker-timers-worker": "^9.0.14"
|
||||
}
|
||||
},
|
||||
"node_modules/worker-timers-worker": {
|
||||
"version": "9.0.14",
|
||||
"resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.14.tgz",
|
||||
"integrity": "sha512-/qF06C60sXmSLfUl7WglvrDIbspmPOM8UrG63Dnn4bi2x4/DfqHS/+dxF5B+MdHnYO5tVuZYLHdAodrKdabTIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"tslib": "^2.8.1",
|
||||
"worker-factory": "^7.0.49"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
||||
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,5 +11,8 @@
|
||||
"devDependencies": {
|
||||
"typescript": "~6.0.2",
|
||||
"vite": "^8.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"mqtt": "^5.15.1"
|
||||
}
|
||||
}
|
||||
|
||||
+186
-28
@@ -1,9 +1,19 @@
|
||||
import mqtt from 'mqtt'
|
||||
import './style.css'
|
||||
|
||||
type Page = 'players' | 'start' | 'info'
|
||||
type Page = 'home' | 'players' | 'start' | 'text'
|
||||
type Route = 'home' | 'maintenance' | 'players' | 'start' | 'text'
|
||||
|
||||
const storageKey = 'players'
|
||||
let players: string[] = loadPlayers()
|
||||
const mqttBrokerHost = '91.99.29.8'
|
||||
const mqttBrokerPort = 9001
|
||||
const mqttBrokerPath = '/mqtt'
|
||||
const mqttUseTls = false
|
||||
const mqttTopic = 'king-arthur/page/startup'
|
||||
const mqttMessage = 'start-hit'
|
||||
|
||||
const initialPlayers = loadPlayers()
|
||||
let players: string[] = []
|
||||
let currentName = ''
|
||||
|
||||
function loadPlayers(): string[] {
|
||||
@@ -26,40 +36,125 @@ function savePlayers(): void {
|
||||
localStorage.setItem(storageKey, JSON.stringify(players))
|
||||
}
|
||||
|
||||
function getPageFromHash(): Page {
|
||||
const hash = window.location.hash.replace('#', '')
|
||||
if (hash === 'start' || hash === 'info' || hash === 'players') {
|
||||
return hash
|
||||
}
|
||||
return 'players'
|
||||
function publishStartHit(): void {
|
||||
const protocol = mqttUseTls ? 'wss' : 'ws'
|
||||
const brokerUrl = `${protocol}://${mqttBrokerHost}:${mqttBrokerPort}${mqttBrokerPath}`
|
||||
const client = mqtt.connect(brokerUrl)
|
||||
|
||||
client.on('connect', () => {
|
||||
client.publish(mqttTopic, mqttMessage, { qos: 1 }, () => {
|
||||
client.end()
|
||||
})
|
||||
})
|
||||
|
||||
client.on('error', (error) => {
|
||||
console.error('MQTT publish failed:', error)
|
||||
client.end(true)
|
||||
})
|
||||
}
|
||||
|
||||
function getRouteFromPath(): Route {
|
||||
const path = window.location.pathname
|
||||
|
||||
if (path === '/') return 'home'
|
||||
if (path === '/maintenance') return 'maintenance'
|
||||
if (path === '/players') return 'players'
|
||||
if (path === '/start') return 'start'
|
||||
if (path === '/text') return 'text'
|
||||
if (path.startsWith('/players')) return 'players'
|
||||
if (path.startsWith('/start')) return 'start'
|
||||
if (path.startsWith('/text')) return 'text'
|
||||
|
||||
return 'home'
|
||||
}
|
||||
|
||||
function navigateTo(path: string): void {
|
||||
window.history.pushState({}, '', path)
|
||||
render()
|
||||
}
|
||||
|
||||
function render(): void {
|
||||
const app = document.querySelector<HTMLDivElement>('#app')
|
||||
if (!app) return
|
||||
|
||||
const page = getPageFromHash()
|
||||
const route = getRouteFromPath()
|
||||
const path = window.location.pathname
|
||||
|
||||
app.innerHTML = `
|
||||
<main class="app">
|
||||
<h1>Simple Player Web App</h1>
|
||||
<nav class="nav">
|
||||
<a href="#players" class="nav-link ${page === 'players' ? 'active' : ''}">Page 1: Players</a>
|
||||
<a href="#start" class="nav-link ${page === 'start' ? 'active' : ''}">Page 2: Start</a>
|
||||
<a href="#info" class="nav-link ${page === 'info' ? 'active' : ''}">Page 3: Text</a>
|
||||
</nav>
|
||||
<section class="page-content">
|
||||
${renderPage(page)}
|
||||
</section>
|
||||
</main>
|
||||
`
|
||||
if (route === 'home') {
|
||||
app.innerHTML = `
|
||||
<main class="app">
|
||||
<section class="page-content">
|
||||
${renderHomePage()}
|
||||
</section>
|
||||
</main>
|
||||
`
|
||||
} else if (path === '/maintenance') {
|
||||
const maintenancePage: Page = 'players'
|
||||
app.innerHTML = `
|
||||
<main class="app">
|
||||
<h1>Simple Player Web App</h1>
|
||||
<nav class="nav">
|
||||
<a href="/players" class="nav-link active">Page 1: Players</a>
|
||||
<a href="/start" class="nav-link">Page 2: Start</a>
|
||||
<a href="/text" class="nav-link">Page 3: Text</a>
|
||||
</nav>
|
||||
<section class="page-content">
|
||||
${renderPage(maintenancePage)}
|
||||
</section>
|
||||
</main>
|
||||
`
|
||||
attachNavigationHandlers(maintenancePage)
|
||||
} else {
|
||||
const page = route as Page
|
||||
app.innerHTML = `
|
||||
<main class="app">
|
||||
<section class="page-content">
|
||||
${renderPage(page)}
|
||||
</section>
|
||||
</main>
|
||||
`
|
||||
attachHandlers(page)
|
||||
}
|
||||
}
|
||||
|
||||
attachHandlers(page)
|
||||
function renderHomePage(): string {
|
||||
return `
|
||||
<div class="home-content">
|
||||
<h1>Welcome to King Arthur</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
||||
<div class="info-section">
|
||||
<div class="info-box">
|
||||
<h3>Version</h3>
|
||||
<p id="version-number">1.0.0</p>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<h3>Service Hotline</h3>
|
||||
<p id="service-hotline">+1 800-123-4567</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="home-nav">
|
||||
<a href="/players" class="nav-button">Players</a>
|
||||
<a href="/start" class="nav-button">Start</a>
|
||||
<a href="/text" class="nav-button">Text</a>
|
||||
<a href="/maintenance" class="nav-button">Maintenance</a>
|
||||
</nav>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function renderPage(page: Page): string {
|
||||
|
||||
if (page === 'players') {
|
||||
const listItems = players.map((name) => `<li>${name}</li>`).join('')
|
||||
const listItems = players.map((name, index) => `
|
||||
<li class="player-item">
|
||||
<span class="player-name">${name}</span>
|
||||
<button class="delete-btn" data-index="${index}" title="Delete player">
|
||||
<svg class="trash-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-9l-1 1H5v2h14V4z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
`).join('')
|
||||
|
||||
return `
|
||||
<h2>Add players</h2>
|
||||
@@ -68,6 +163,10 @@ function renderPage(page: Page): string {
|
||||
<button id="add-player" type="button">Add</button>
|
||||
</div>
|
||||
<ul class="player-list">${listItems}</ul>
|
||||
<div class="players-actions">
|
||||
<button id="clear-all-btn" type="button" class="btn-secondary">Clear All</button>
|
||||
<button id="finished-btn" type="button" class="btn-primary">Finished</button>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -87,10 +186,43 @@ function renderPage(page: Page): string {
|
||||
`
|
||||
}
|
||||
|
||||
function attachNavigationHandlers(page: Page): void {
|
||||
const navLinks = document.querySelectorAll<HTMLAnchorElement>('.nav-link')
|
||||
navLinks.forEach((link) => {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
const href = link.getAttribute('href')
|
||||
if (href) {
|
||||
navigateTo(href)
|
||||
updateActiveNavLink(page)
|
||||
}
|
||||
})
|
||||
})
|
||||
attachHandlers(page)
|
||||
}
|
||||
|
||||
function updateActiveNavLink(page: Page): void {
|
||||
const navLinks = document.querySelectorAll<HTMLAnchorElement>('.nav-link')
|
||||
navLinks.forEach((link) => {
|
||||
link.classList.remove('active')
|
||||
const href = link.getAttribute('href')
|
||||
if (
|
||||
(page === 'players' && href === '/players') ||
|
||||
(page === 'start' && href === '/start') ||
|
||||
(page === 'text' && href === '/text')
|
||||
) {
|
||||
link.classList.add('active')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function attachHandlers(page: Page): void {
|
||||
if (page === 'players') {
|
||||
const input = document.querySelector<HTMLInputElement>('#player-input')
|
||||
const button = document.querySelector<HTMLButtonElement>('#add-player')
|
||||
const deleteButtons = document.querySelectorAll<HTMLButtonElement>('.delete-btn')
|
||||
const clearAllBtn = document.querySelector<HTMLButtonElement>('#clear-all-btn')
|
||||
const finishedBtn = document.querySelector<HTMLButtonElement>('#finished-btn')
|
||||
|
||||
if (input && button) {
|
||||
const addPlayer = () => {
|
||||
@@ -110,6 +242,31 @@ function attachHandlers(page: Page): void {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteButtons.forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
const index = parseInt(btn.getAttribute('data-index') || '0', 10)
|
||||
players.splice(index, 1)
|
||||
savePlayers()
|
||||
render()
|
||||
})
|
||||
})
|
||||
|
||||
if (clearAllBtn) {
|
||||
clearAllBtn.addEventListener('click', () => {
|
||||
if (confirm('Are you sure you want to delete all players?')) {
|
||||
players = []
|
||||
savePlayers()
|
||||
render()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (finishedBtn) {
|
||||
finishedBtn.addEventListener('click', () => {
|
||||
window.location.href = '/start'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (page === 'start') {
|
||||
@@ -118,11 +275,12 @@ function attachHandlers(page: Page): void {
|
||||
|
||||
if (button && selectedName) {
|
||||
button.addEventListener('click', () => {
|
||||
publishStartHit()
|
||||
if (players.length === 0) {
|
||||
currentName = 'Please add players on page 1 first.'
|
||||
} else {
|
||||
const randomIndex = Math.floor(Math.random() * players.length)
|
||||
currentName = players[randomIndex]
|
||||
currentName = (players[randomIndex])
|
||||
}
|
||||
selectedName.textContent = currentName
|
||||
})
|
||||
@@ -130,10 +288,10 @@ function attachHandlers(page: Page): void {
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', render)
|
||||
window.addEventListener('popstate', render)
|
||||
|
||||
if (!window.location.hash) {
|
||||
window.location.hash = '#players'
|
||||
if (window.location.pathname === '/' || !window.location.pathname.startsWith('/')) {
|
||||
window.history.replaceState({}, '', '/')
|
||||
}
|
||||
|
||||
render()
|
||||
|
||||
+153
-5
@@ -93,13 +93,161 @@ button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.player-list {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#selected-name {
|
||||
margin-top: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.home-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.home-content h1 {
|
||||
margin: 0 0 16px;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.home-content p {
|
||||
margin: 0 0 24px;
|
||||
line-height: 1.6;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin: 32px 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
flex: 1;
|
||||
max-width: 200px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.info-box h3 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.home-nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
background: #111827;
|
||||
border: 1px solid #111827;
|
||||
border-radius: 8px;
|
||||
padding: 12px 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.nav-button:hover {
|
||||
background: #374151;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
.player-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.player-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
margin: 8px 0;
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.player-name {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: #ef4444;
|
||||
border: 1px solid #ef4444;
|
||||
color: #ffffff;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background: #dc2626;
|
||||
border-color: #dc2626;
|
||||
}
|
||||
|
||||
.trash-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.players-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #111827;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #e5e7eb;
|
||||
color: #111827;
|
||||
border: 1px solid #d1d5db;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #d1d5db;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user