diff --git a/README.md b/README.md
index b37bd21..cbd8b5b 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,8 @@ Oxford debate (pl. _[debata oksfordzka](https://pl.wikipedia.org/wiki/Debata_oks
- Debate clock adjustable to rules of any tournament,
- Generator of motions used in past tournaments with filtering by type and language,
- Usable logos of tournaments that used Debate Tools,
-- Submitting custom logos.
+- Submitting custom logos,
+- Sharing debate configurations via links.
## Origin
@@ -34,7 +35,7 @@ Debate Tools were first used and tested in ZSK Poznań, during the 2023/2024 edi
## License
-Copyright © 2023-2024 Jakub Mańczak & Mateusz Dobrzyński
+Copyright © 2023-2025 Jakub Mańczak & Mateusz Dobrzyński
Unless stated otherwise in `LEGAL.md` regarding specific files, Debate Tools are distributed under [AGPL-3.0-only](LICENSE).
diff --git a/package-lock.json b/package-lock.json
index 7a05ae4..2d3cc28 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.12",
"flag-icons": "^7.2.2",
+ "fs": "^0.0.1-security",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jsdom": "24.1.0",
@@ -24,7 +25,7 @@
"use-sound": "^4.0.1"
},
"devDependencies": {
- "@playwright/test": "^1.45.1",
+ "@playwright/test": "^1.51.0",
"@testing-library/dom": "^10.1.0",
"@testing-library/react": "^16.0.0",
"@types/node": "^20",
@@ -1328,9 +1329,9 @@
}
},
"node_modules/@next/env": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz",
- "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.24.tgz",
+ "integrity": "sha512-LAm0Is2KHTNT6IT16lxT+suD0u+VVfYNQqM+EJTKuFRRuY2z+zj01kueWXPCxbMBDt0B5vONYzabHGUNbZYAhA==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@@ -1343,12 +1344,13 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz",
- "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.24.tgz",
+ "integrity": "sha512-7Tdi13aojnAZGpapVU6meVSpNzgrFwZ8joDcNS8cJVNuP3zqqrLqeory9Xec5TJZR/stsGJdfwo8KeyloT3+rQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1358,12 +1360,13 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz",
- "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.24.tgz",
+ "integrity": "sha512-lXR2WQqUtu69l5JMdTwSvQUkdqAhEWOqJEYUQ21QczQsAlNOW2kWZCucA6b3EXmPbcvmHB1kSZDua/713d52xg==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1373,12 +1376,13 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz",
- "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.24.tgz",
+ "integrity": "sha512-nxvJgWOpSNmzidYvvGDfXwxkijb6hL9+cjZx1PVG6urr2h2jUqBALkKjT7kpfurRWicK6hFOvarmaWsINT1hnA==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1388,12 +1392,13 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz",
- "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.24.tgz",
+ "integrity": "sha512-PaBgOPhqa4Abxa3y/P92F3kklNPsiFjcjldQGT7kFmiY5nuFn8ClBEoX8GIpqU1ODP2y8P6hio6vTomx2Vy0UQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1403,9 +1408,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz",
- "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.24.tgz",
+ "integrity": "sha512-vEbyadiRI7GOr94hd2AB15LFVgcJZQWu7Cdi9cWjCMeCiUsHWA0U5BkGPuoYRnTxTn0HacuMb9NeAmStfBCLoQ==",
"cpu": [
"x64"
],
@@ -1419,12 +1424,13 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz",
- "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.24.tgz",
+ "integrity": "sha512-df0FC9ptaYsd8nQCINCzFtDWtko8PNRTAU0/+d7hy47E0oC17tI54U/0NdGk7l/76jz1J377dvRjmt6IUdkpzQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1434,12 +1440,13 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz",
- "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.24.tgz",
+ "integrity": "sha512-ZEntbLjeYAJ286eAqbxpZHhDFYpYjArotQ+/TW9j7UROh0DUmX7wYDGtsTPpfCV8V+UoqHBPU7q9D4nDNH014Q==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1449,12 +1456,13 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz",
- "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.24.tgz",
+ "integrity": "sha512-9KuS+XUXM3T6v7leeWU0erpJ6NsFIwiTFD5nzNg8J5uo/DMIPvCp3L1Ao5HjbHX0gkWPB1VrKoo/Il4F0cGK2Q==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1464,12 +1472,13 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz",
- "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.24.tgz",
+ "integrity": "sha512-cXcJ2+x0fXQ2CntaE00d7uUH+u1Bfp/E0HsNQH79YiLaZE5Rbm7dZzyAYccn3uICM7mw+DxoMqEfGXZtF4Fgaw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1524,13 +1533,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.45.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.1.tgz",
- "integrity": "sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==",
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.0.tgz",
+ "integrity": "sha512-dJ0dMbZeHhI+wb77+ljx/FeC8VBP6j/rj9OAojO08JI80wTZy6vRk9KvHKiDCUh4iMpEiseMgqRBIeW+eKX6RA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.45.1"
+ "playwright": "1.51.0"
},
"bin": {
"playwright": "cli.js"
@@ -2655,9 +2664,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001579",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
- "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
+ "version": "1.0.30001703",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001703.tgz",
+ "integrity": "sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==",
"funding": [
{
"type": "opencollective",
@@ -2671,7 +2680,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ]
+ ],
+ "license": "CC-BY-4.0"
},
"node_modules/chalk": {
"version": "4.1.2",
@@ -2913,9 +2923,10 @@
"license": "MIT"
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -3934,9 +3945,10 @@
"dev": true
},
"node_modules/fast-loops": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz",
- "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g=="
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.4.tgz",
+ "integrity": "sha512-8dbd3XWoKCTms18ize6JmQF1SFnnfj5s0B7rRry22EofgMu7B6LKHVh+XfFqFGsqnbH54xgeO83PzpKI+ODhlg==",
+ "license": "MIT"
},
"node_modules/fast-shallow-equal": {
"version": "1.0.0",
@@ -4083,11 +4095,31 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/fs": {
+ "version": "0.0.1-security",
+ "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
+ "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==",
+ "license": "ISC"
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -6483,11 +6515,12 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -6589,15 +6622,16 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -6611,12 +6645,12 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
},
"node_modules/next": {
- "version": "14.2.4",
- "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz",
- "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/next/-/next-14.2.24.tgz",
+ "integrity": "sha512-En8VEexSJ0Py2FfVnRRh8gtERwDRaJGNvsvad47ShkC2Yi8AXQPXEA2vKoDJlGFSj5WE5SyF21zNi4M5gyi+SQ==",
"license": "MIT",
"dependencies": {
- "@next/env": "14.2.4",
+ "@next/env": "14.2.24",
"@swc/helpers": "0.5.5",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
@@ -6631,15 +6665,15 @@
"node": ">=18.17.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.2.4",
- "@next/swc-darwin-x64": "14.2.4",
- "@next/swc-linux-arm64-gnu": "14.2.4",
- "@next/swc-linux-arm64-musl": "14.2.4",
- "@next/swc-linux-x64-gnu": "14.2.4",
- "@next/swc-linux-x64-musl": "14.2.4",
- "@next/swc-win32-arm64-msvc": "14.2.4",
- "@next/swc-win32-ia32-msvc": "14.2.4",
- "@next/swc-win32-x64-msvc": "14.2.4"
+ "@next/swc-darwin-arm64": "14.2.24",
+ "@next/swc-darwin-x64": "14.2.24",
+ "@next/swc-linux-arm64-gnu": "14.2.24",
+ "@next/swc-linux-arm64-musl": "14.2.24",
+ "@next/swc-linux-x64-gnu": "14.2.24",
+ "@next/swc-linux-x64-musl": "14.2.24",
+ "@next/swc-win32-arm64-msvc": "14.2.24",
+ "@next/swc-win32-ia32-msvc": "14.2.24",
+ "@next/swc-win32-x64-msvc": "14.2.24"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -7132,13 +7166,13 @@
}
},
"node_modules/playwright": {
- "version": "1.45.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.1.tgz",
- "integrity": "sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==",
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.0.tgz",
+ "integrity": "sha512-442pTfGM0xxfCYxuBa/Pu6B2OqxqqaYq39JS8QDMGThUvIOCd6s0ANDog3uwA0cHavVlnTQzGCN7Id2YekDSXA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.45.1"
+ "playwright-core": "1.51.0"
},
"bin": {
"playwright": "cli.js"
@@ -7151,9 +7185,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.45.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.1.tgz",
- "integrity": "sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==",
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.0.tgz",
+ "integrity": "sha512-x47yPE3Zwhlil7wlNU/iktF7t2r/URR3VLbH6EknJd/04Qc/PSJ0EY3CMXipmglLG+zyRxW6HNo2EGbKLHPWMg==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -7163,21 +7197,6 @@
"node": ">=18"
}
},
- "node_modules/playwright/node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/postcss": {
"version": "8.4.33",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
diff --git a/package.json b/package.json
index 993a59c..fa55ab0 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.12",
"flag-icons": "^7.2.2",
+ "fs": "^0.0.1-security",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jsdom": "24.1.0",
@@ -26,7 +27,7 @@
"use-sound": "^4.0.1"
},
"devDependencies": {
- "@playwright/test": "^1.45.1",
+ "@playwright/test": "^1.51.0",
"@testing-library/dom": "^10.1.0",
"@testing-library/react": "^16.0.0",
"@types/node": "^20",
@@ -38,5 +39,10 @@
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
+ },
+ "browser": {
+ "fs": false,
+ "path": false,
+ "os": false
}
}
diff --git a/playwright.config.ts b/playwright.config.ts
index be844e1..2c001df 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -35,9 +35,11 @@ export default defineConfig({
projects: [
{
name: "chromium",
- use: { ...devices["Desktop Chrome"] },
+ use: {
+ ...devices["Desktop Chrome"],
+ permissions: ["clipboard-read", "clipboard-write"],
+ },
},
-
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
diff --git a/src/app/oxford-debate/page.tsx b/src/app/oxford-debate/page.tsx
index 5e7ffe5..a09949f 100644
--- a/src/app/oxford-debate/page.tsx
+++ b/src/app/oxford-debate/page.tsx
@@ -156,7 +156,9 @@ export default function OxfordDebate() {
{/* debate finished */}
{stage === 8 && (
-
{debateFinishedEnthusiastic}
+
+ {debateFinishedEnthusiastic}
+
{"🎉"}
)}
diff --git a/src/app/oxford-debate/setup/page.tsx b/src/app/oxford-debate/setup/page.tsx
index 71f062a..6820f5f 100644
--- a/src/app/oxford-debate/setup/page.tsx
+++ b/src/app/oxford-debate/setup/page.tsx
@@ -10,16 +10,26 @@ import { IconPlayCircle } from "@/components/icons/PlayCircle";
import { IconX } from "@/components/icons/X";
import { DebateContext } from "@/contexts/DebateContext";
import { useLang } from "@/lib/useLang";
-import { displayImageType, displayImageTypeArray } from "@/types/debate";
-import { useContext, useEffect, useState } from "react";
+import {
+ debateConf,
+ defaultDebateConf,
+ displayImageType,
+ displayImageTypeArray,
+} from "@/types/debate";
+import { useContext, useEffect, useRef, useState } from "react";
import {
defaultSoundPack,
soundPackName,
soundPackNamesArray,
soundPacks,
+ ztmPoznańSoundPack,
} from "@/types/soundPack";
import { convertImageToBase64 } from "@/lib/imageToBase64";
import { DebatecoreFooter } from "@/components/DebatecoreFooter";
+import { IconClipboard } from "@/components/icons/Clipboard";
+import { useEffectOnce } from "react-use";
+import { toast, Toaster } from "sonner";
+import Link from "next/link";
export default function OxfordDebateSetup() {
const debateContext = useContext(DebateContext);
@@ -31,6 +41,8 @@ export default function OxfordDebateSetup() {
const soundPackDefault = useLang("defaultSoundsOption");
const [customClockImageSelected, setCustomClockImageSelected] =
useState(false);
+ const initializedRef = useRef(false);
+ const debateCopiedMessage = useLang("debateCopiedSuccess");
const getDisplayNameOfClockImage = (clockImageName: string) => {
switch (clockImageName) {
@@ -68,10 +80,137 @@ export default function OxfordDebateSetup() {
} else {
setCustomClockImageSelected(false);
}
+ initializedRef.current = true;
+ }, [setCustomClockImageSelected, debateContext.conf.clockImageName]);
+
+ const parseUrlParams = () => {
+ const queryString = window.location.search;
+ const urlParams = new URLSearchParams(queryString);
+ const conf: debateConf = {
+ motion: urlParams.get("motion") || defaultDebateConf.motion,
+ proTeam: urlParams.get("proTeam") || defaultDebateConf.proTeam,
+ oppTeam: urlParams.get("oppTeam") || defaultDebateConf.oppTeam,
+ speechTime:
+ parseInt(urlParams.get("speechTime") || "") ||
+ defaultDebateConf.speechTime,
+ adVocemTime:
+ parseInt(urlParams.get("adVocemTime") || "") ||
+ defaultDebateConf.adVocemTime,
+ endProtectedTime:
+ parseInt(urlParams.get("endProtectedTime") || "") ||
+ defaultDebateConf.endProtectedTime,
+ startProtectedTime:
+ parseInt(urlParams.get("startProtectedTime") || "") ||
+ defaultDebateConf.startProtectedTime,
+ beepOnSpeechEnd: getBooleanParamValue("beepOnSpeechEnd", urlParams),
+ beepProtectedTime: getBooleanParamValue("beepProtectedTime", urlParams),
+ visualizeProtectedTimes: false,
+ clockImageName: parseClockImageName(
+ urlParams.get("clockImageName"),
+ urlParams.get("customClockImageLink")
+ ),
+ customClockImageBase64: "",
+ customClockImageLink: urlParams.get("customClockImageLink") || "",
+ soundPack: getSoundPack(urlParams),
+ };
+ return conf;
+ };
+
+ useEffectOnce(() => {
+ let confFromParams = parseUrlParams();
+ if (
+ debateContext.conf == defaultDebateConf &&
+ confFromParams != defaultDebateConf
+ ) {
+ debateContext.setConf(confFromParams);
+ }
});
+ function getBooleanParamValue(
+ param: "beepOnSpeechEnd" | "beepProtectedTime",
+ urlParams: URLSearchParams
+ ): boolean {
+ const paramValue = parseAsBoolean(urlParams.get(param));
+ if (paramValue != undefined) {
+ return paramValue;
+ } else if (param == "beepOnSpeechEnd") {
+ return defaultDebateConf.beepOnSpeechEnd;
+ } else if (param == "beepProtectedTime") {
+ return defaultDebateConf.beepProtectedTime;
+ } else {
+ throw Error("Invalid boolean param");
+ }
+ }
+
+ function parseAsBoolean(value: string | null): boolean | undefined {
+ if (value == "true") {
+ return true;
+ } else if (value == "false") {
+ return false;
+ } else {
+ return undefined;
+ }
+ }
+
+ function getSoundPack(urlParams: URLSearchParams) {
+ const soundPack = urlParams.get("soundPack");
+ if (soundPack == undefined) {
+ return defaultSoundPack;
+ }
+ if (decodeURI(soundPack) == "ZTM Poznań") {
+ return ztmPoznańSoundPack;
+ } else {
+ return defaultSoundPack;
+ }
+ }
+
+ function parseClockImageName(
+ name: string | null,
+ clockImageLink: string | null
+ ): displayImageType {
+ if (displayImageTypeArray.includes(name as any)) {
+ return name as displayImageType;
+ } else if (!displayImageTypeArray.includes(name as any) && clockImageLink) {
+ return "custom";
+ } else return "null";
+ }
+
+ function copyDebateConfigurationLink() {
+ const currentDebateConf = debateContext.conf;
+ const params = [];
+ let param: keyof debateConf;
+ for (param in currentDebateConf) {
+ if (
+ currentDebateConf[param] != defaultDebateConf[param] &&
+ param != "soundPack"
+ ) {
+ params.push(`${param}=${currentDebateConf[param]}`);
+ }
+ }
+ let link = `${
+ location.protocol + "//" + location.host + location.pathname
+ }`;
+ if (params.length == 0) {
+ navigator.clipboard.writeText(link);
+ } else {
+ link += "?";
+ params.forEach((param) => {
+ link += `&${param}`;
+ });
+ if (
+ currentDebateConf.soundPack.name != defaultDebateConf.soundPack.name
+ ) {
+ link += `&soundPack=${currentDebateConf.soundPack.name}`;
+ }
+ navigator.clipboard.writeText(encodeURI(link));
+ console.log(link);
+ }
+ toast.success(debateCopiedMessage);
+ }
+
return (
+
{useLang("oxfordDebateConfiguration")}
@@ -199,6 +338,13 @@ export default function OxfordDebateSetup() {
+
+
copyDebateConfigurationLink()}
+ text={useLang("copyDebateConfiguration")}
+ icon={IconClipboard}
+ />
+
{
const [clockImageLoaded, setClockImageLoaded] = useState(false);
const loadingText = useLang("loading");
+ function getImageSource() {
+ if (
+ currentDebateConf.clockImageName == "custom" &&
+ currentDebateConf.customClockImageBase64 != ""
+ ) {
+ return `data:image/png;base64, ${currentDebateConf.customClockImageBase64}`;
+ } else if (
+ currentDebateConf.clockImageName == "custom" &&
+ currentDebateConf.customClockImageLink != ""
+ ) {
+ return currentDebateConf.customClockImageLink;
+ } else {
+ return "";
+ }
+ }
+
return (
{
/>
)}
{clockImageName === "custom" &&
- currentDebateConf.customClockImageBase64 != "" && (
+ currentDebateConf.customClockImageBase64 != "" &&
+ currentDebateConf.customClockImageLink == "" && (
setClockImageLoaded(true)}
+ data-loaded={clockImageLoaded}
+ />
+ )}
+ {clockImageName === "custom" &&
+ currentDebateConf.customClockImageLink != "" && (
+
{
{useLang("disclaimer")}
- {" © 2023-2024 Jakub Mańczak & Mateusz Dobrzyński"}
+ {" © 2023-2025 Jakub Mańczak & Mateusz Dobrzyński"}
>
);
diff --git a/src/components/TimeInput.tsx b/src/components/TimeInput.tsx
index 84e1b5a..6a6d783 100644
--- a/src/components/TimeInput.tsx
+++ b/src/components/TimeInput.tsx
@@ -29,7 +29,7 @@ const TimeInput = (props: {
{minutesCount}
- {` ${minutesGrammaticalNumber}`}
+ {` ${minutesGrammaticalNumber}`}