diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..acf9a26 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/flbxcup.iml b/.idea/flbxcup.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/flbxcup.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..a351215 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7e732a9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/bun.lock b/bun.lock index 010584b..48781f4 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ "drizzle-orm": "^0.40.0", "drizzle-zod": "^0.8.2", "lucide-svelte": "^0.525.0", - "postgres": "^3.4.5", + "pg": "^8.16.3", "svelte-i18n": "^4.0.1", "svelvet": "^11.0.5", "uuid": "^11.1.0", @@ -27,6 +27,7 @@ "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", "@types/node": "^22", + "@types/pg": "^8.15.4", "bits-ui": "^2.8.6", "clsx": "^2.1.1", "drizzle-kit": "^0.30.2", @@ -59,6 +60,8 @@ "@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="], + "@bufbuild/protobuf": ["@bufbuild/protobuf@2.6.0", "", {}, "sha512-6cuonJVNOIL7lTj5zgo/Rc2bKAo4/GvN+rKCrUj7GdEHRzCk8zKOfFwUsL9nAVk5rSIsRmlgcpLzTRysopEeeg=="], + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], "@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], @@ -363,6 +366,8 @@ "@types/node": ["@types/node@22.16.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ=="], + "@types/pg": ["@types/pg@8.15.4", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg=="], + "@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="], "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], @@ -391,6 +396,8 @@ "bits-ui": ["bits-ui@2.8.10", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.29.1", "svelte-toolbelt": "^0.9.3", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-MOobkqapDZNrpcNmeL2g664xFmH4tZBOKBTxFmsQYMZQuybSZHQnPXy+AjM5XZEXRmCFx5+XRmo6+fC3vHh1hQ=="], + "buffer-builder": ["buffer-builder@0.2.0", "", {}, "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="], @@ -407,6 +414,8 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "colorjs.io": ["colorjs.io@0.5.2", "", {}, "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw=="], + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], @@ -489,8 +498,12 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "immutable": ["immutable@5.1.3", "", {}, "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg=="], + "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], "intl-messageformat": ["intl-messageformat@10.7.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.2", "tslib": "^2.8.0" } }, "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug=="], @@ -581,6 +594,22 @@ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + "pg": ["pg@8.16.3", "", { "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", "pg-protocol": "^1.10.3", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.2.7" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw=="], + + "pg-cloudflare": ["pg-cloudflare@1.2.7", "", {}, "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg=="], + + "pg-connection-string": ["pg-connection-string@2.9.1", "", {}, "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.10.1", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg=="], + + "pg-protocol": ["pg-protocol@1.10.3", "", {}, "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], @@ -591,6 +620,14 @@ "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], + "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "prettier-plugin-svelte": ["prettier-plugin-svelte@3.4.0", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ=="], @@ -613,8 +650,44 @@ "runed": ["runed@0.29.1", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-RGQEB8ZiWv4OvzBJhbMj2hMgRM8QrEptzTrDr7TDfkHaRePKjiUka4vJ9QHGY+8s87KymNvFoZAxFdQ4jtZNcA=="], + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + "sass-embedded": ["sass-embedded@1.89.2", "", { "dependencies": { "@bufbuild/protobuf": "^2.5.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.89.2", "sass-embedded-android-arm64": "1.89.2", "sass-embedded-android-riscv64": "1.89.2", "sass-embedded-android-x64": "1.89.2", "sass-embedded-darwin-arm64": "1.89.2", "sass-embedded-darwin-x64": "1.89.2", "sass-embedded-linux-arm": "1.89.2", "sass-embedded-linux-arm64": "1.89.2", "sass-embedded-linux-musl-arm": "1.89.2", "sass-embedded-linux-musl-arm64": "1.89.2", "sass-embedded-linux-musl-riscv64": "1.89.2", "sass-embedded-linux-musl-x64": "1.89.2", "sass-embedded-linux-riscv64": "1.89.2", "sass-embedded-linux-x64": "1.89.2", "sass-embedded-win32-arm64": "1.89.2", "sass-embedded-win32-x64": "1.89.2" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA=="], + + "sass-embedded-android-arm": ["sass-embedded-android-arm@1.89.2", "", { "os": "android", "cpu": "arm" }, "sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A=="], + + "sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.89.2", "", { "os": "android", "cpu": "arm64" }, "sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA=="], + + "sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.89.2", "", { "os": "android", "cpu": "none" }, "sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg=="], + + "sass-embedded-android-x64": ["sass-embedded-android-x64@1.89.2", "", { "os": "android", "cpu": "x64" }, "sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA=="], + + "sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.89.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw=="], + + "sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.89.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA=="], + + "sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.89.2", "", { "os": "linux", "cpu": "arm" }, "sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA=="], + + "sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.89.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ=="], + + "sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.89.2", "", { "os": "linux", "cpu": "arm" }, "sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g=="], + + "sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.89.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw=="], + + "sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.89.2", "", { "os": "linux", "cpu": "none" }, "sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw=="], + + "sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.89.2", "", { "os": "linux", "cpu": "x64" }, "sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg=="], + + "sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.89.2", "", { "os": "linux", "cpu": "none" }, "sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w=="], + + "sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.89.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ=="], + + "sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.89.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg=="], + + "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.89.2", "", { "os": "win32", "cpu": "x64" }, "sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng=="], + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], @@ -629,10 +702,14 @@ "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="], "superstruct": ["superstruct@2.0.2", "", {}, "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A=="], + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "svelte": ["svelte@5.35.2", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-uW/rRXYrhZ7Dh4UQNZ0t+oVGL1dEM+95GavCO8afAk1IY2cPq9BcZv9C3um5aLIya2y8lIeLPxLII9ASGg9Dzw=="], @@ -649,6 +726,10 @@ "svelvet": ["svelvet@11.0.5", "", { "dependencies": { "svelvet": "^10.0.2", "uuid": "^11.0.5" }, "peerDependencies": { "svelte": ">=3.59.2 || ^4.0.0" } }, "sha512-wGDGh3bRKK06stu613DC+r4ujE7sWkFTAp4bfW6Impc2A89Ix0M/PzZAyeW229FMS5TF2GRDugHgpk0q0D8k2g=="], + "sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="], + + "sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="], + "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="], @@ -697,6 +778,8 @@ "validator": ["validator@13.15.15", "", {}, "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A=="], + "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="], + "vite": ["rolldown-vite@7.0.4", "", { "dependencies": { "@oxc-project/runtime": "0.75.0", "fdir": "^6.4.6", "lightningcss": "^1.30.1", "picomatch": "^4.0.2", "postcss": "^8.5.6", "rolldown": "1.0.0-beta.23", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "esbuild": "^0.25.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-AcFt2mBWuwH3svDHcz8V5+K8Es1TuZOBDdJh6+ySkGSuNS5sEpRJqnopupeMfB8SHCAXVA6Wp75OQmTBZc+TgQ=="], "vite-plugin-devtools-json": ["vite-plugin-devtools-json@0.2.1", "", { "dependencies": { "uuid": "^11.1.0" }, "peerDependencies": { "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-5aiNvf/iLTuLR1dUqoI5CLLGgeK2hd6u+tA+RIp7GUZDyAcM6ECaUEWOOtGpidbcxbkKq++KtmSqA3jhMbPwMA=="], @@ -705,6 +788,8 @@ "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yup": ["yup@1.6.1", "", { "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", "toposort": "^2.0.2", "type-fest": "^2.19.0" } }, "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA=="], diff --git a/package.json b/package.json index f7ed3c3..1056d98 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", "@types/node": "^22", + "@types/pg": "^8.15.4", "bits-ui": "^2.8.6", "clsx": "^2.1.1", "drizzle-kit": "^0.30.2", @@ -56,7 +57,7 @@ "drizzle-orm": "^0.40.0", "drizzle-zod": "^0.8.2", "lucide-svelte": "^0.525.0", - "postgres": "^3.4.5", + "pg": "^8.16.3", "svelte-i18n": "^4.0.1", "svelvet": "^11.0.5", "uuid": "^11.1.0", diff --git a/src/lib/components/app-layout.svelte b/src/lib/components/app-layout.svelte index f8c6b54..4096c0c 100644 --- a/src/lib/components/app-layout.svelte +++ b/src/lib/components/app-layout.svelte @@ -10,24 +10,40 @@ import { getContext } from 'svelte'; import Nav from '$lib/components/nav.svelte'; import type { User } from '$lib/server/db/schema/users'; + import ThemeToggle from './theme-toggle.svelte'; let { breadcrumbs, className, + fullWidth = false, children - }: { breadcrumbs: BreadcrumbItemType[]; className?: string; children: any } = $props(); + }: { + breadcrumbs: BreadcrumbItemType[]; + className?: string; + fullWidth?: boolean; + children: any; + } = $props(); const user = getContext('user'); -
+
-
-
-
+
+
+ +
+
+ {#if user}
Welcome, {user.username || 'User'} @@ -38,9 +54,6 @@ {/if}
-
-
diff --git a/src/lib/components/brackets/bracket.svelte b/src/lib/components/brackets/bracket.svelte new file mode 100644 index 0000000..b364600 --- /dev/null +++ b/src/lib/components/brackets/bracket.svelte @@ -0,0 +1,26 @@ + + + + {bracket.name} + + {#if !bracket.rounds || bracket.rounds.length <= 0} + No matches + {:else} + {bracket.rounds[bracket.position - 1].name} ({bracket.position}/{bracket.rounds.length}) + {/if} + + + diff --git a/src/lib/components/rounds/create-round.svelte b/src/lib/components/brackets/create-bracket.svelte similarity index 75% rename from src/lib/components/rounds/create-round.svelte rename to src/lib/components/brackets/create-bracket.svelte index abae1e4..72b1c2f 100644 --- a/src/lib/components/rounds/create-round.svelte +++ b/src/lib/components/brackets/create-bracket.svelte @@ -7,6 +7,7 @@ import Label from '$ui/label/label.svelte'; import RadioGroupItem from '$ui/radio-group/radio-group-item.svelte'; import RadioGroup from '$ui/radio-group/radio-group.svelte'; + import type { Bracket } from '@/lib/server/db/schema/brackets'; import type { Round } from '@/lib/server/db/schema/rounds'; import { cn, instanceOf } from '@/lib/utils'; import { SchedulingMode } from '@/types'; @@ -19,15 +20,17 @@ let { competitionId, - rounds = $bindable(), - showAddRound = $bindable(true) - }: { competitionId: string; rounds: Round[]; showAddRound: boolean } = $props(); + brackets = $bindable(), + showAddBracket = $bindable(true) + }: { competitionId: string; brackets: Bracket[]; showAddBracket: boolean } = $props(); let schedulingMode: SchedulingMode = $state(SchedulingMode.single); let name = $state(''); let nameInvalid = $state(false); - let nbMatches: number | undefined = $state(); - let nbMatchesInvalid = $state(false); + let size: number | undefined = $state(); + let sizeInvalid = $state(false); + + let buttonDisabled = $state(false); async function submit() { if (name.length === 0) { @@ -35,25 +38,27 @@ toast.error('Name is required'); return; } - if (!nbMatches || nbMatches < 0) { - nbMatchesInvalid = true; + if (!size || size < 0) { + sizeInvalid = true; toast.error('Number of matches must be greater than 0'); return; } nameInvalid = false; + // loading/disable button + buttonDisabled = true; const response = await fetch(`/api/competitions/${competitionId}`, { method: 'POST', credentials: 'include', - body: JSON.stringify({ scheduling_mode: schedulingMode, name: name, nb_matches: nbMatches }) + body: JSON.stringify({ scheduling_mode: schedulingMode, name: name, size: size }) }); - console.log('response', response); // update rounds const data = await response.json(); - if (instanceOf(data, 'id')) { - rounds = [...rounds, data]; - showAddRound = false; + buttonDisabled = false; + if (Array.isArray(data) && data.length > 0 && instanceOf(data[0], 'id')) { + brackets = [...brackets, data[0]]; + showAddBracket = false; } else { - throw new Error('Invalid round'); + throw new Error('Invalid bracket'); } } @@ -65,8 +70,8 @@ - Size* Number of participants at the beginning of the stage. @@ -80,10 +85,10 @@ placeholder="Name" />
@@ -110,6 +115,6 @@ {/each}
- +
diff --git a/src/lib/components/brackets/match.svelte b/src/lib/components/brackets/match.svelte new file mode 100644 index 0000000..6152424 --- /dev/null +++ b/src/lib/components/brackets/match.svelte @@ -0,0 +1,173 @@ + + + + +
+
+
+ Team {match.team1?.name} +
+ + + +
+
+ +
+ Team {match.team2?.name} +
+ + + +
+
+
+
+
+
+ + diff --git a/src/lib/components/brackets/round.svelte b/src/lib/components/brackets/round.svelte new file mode 100644 index 0000000..09693a3 --- /dev/null +++ b/src/lib/components/brackets/round.svelte @@ -0,0 +1,40 @@ + + +
+
+

{round.name}

+
+
+ {@render children()} +
+
+ + diff --git a/src/lib/components/brackets/types/double.svelte b/src/lib/components/brackets/types/double.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/components/brackets/types/double_round_robin.svelte b/src/lib/components/brackets/types/double_round_robin.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/components/brackets/types/round_robin.svelte b/src/lib/components/brackets/types/round_robin.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/components/brackets/types/single.svelte b/src/lib/components/brackets/types/single.svelte new file mode 100644 index 0000000..917a9af --- /dev/null +++ b/src/lib/components/brackets/types/single.svelte @@ -0,0 +1,52 @@ + + +{#if bracket && bracket.rounds} +
+
+

{bracket.name}

+
+
+ {#each bracket.rounds as round, index} + {#if round && round.matches} + + {#each round.matches as match} + + {/each} + + {/if} + {/each} +
+
+{/if} + + diff --git a/src/lib/components/brackets/types/swiss.svelte b/src/lib/components/brackets/types/swiss.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/components/rounds/create-schema.ts b/src/lib/components/rounds/create-schema.ts deleted file mode 100644 index d76c88b..0000000 --- a/src/lib/components/rounds/create-schema.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SchedulingMode } from '@/types'; -import z from 'zod'; - -export const formSchema = z.object({ - scheduling_mode: z.nativeEnum(SchedulingMode) -}); - -export type FormSchema = typeof formSchema; diff --git a/src/lib/components/rounds/round.svelte b/src/lib/components/rounds/round.svelte deleted file mode 100644 index 88a3d05..0000000 --- a/src/lib/components/rounds/round.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - - Round {round.name} - - {#if !round.matches || round.matches.length <= 0} - No matches, add some ! - {:else} - Matches :{#each round.matches as match (match.id)} - {JSON.stringify(match)} - {/each} - {/if} - - - diff --git a/src/lib/components/theme-toggle.svelte b/src/lib/components/theme-toggle.svelte new file mode 100644 index 0000000..668b0fb --- /dev/null +++ b/src/lib/components/theme-toggle.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte index 16f1a3c..4daf453 100644 --- a/src/lib/components/ui/button/button.svelte +++ b/src/lib/components/ui/button/button.svelte @@ -1,36 +1,36 @@ @@ -58,15 +58,15 @@ {/snippet} -{#if captionLayout === 'dropdown'} +{#if captionLayout === "dropdown"} {@render MonthSelect()} {@render YearSelect()} -{:else if captionLayout === 'dropdown-months'} +{:else if captionLayout === "dropdown-months"} {@render MonthSelect()} {#if placeholder} {formatYear(placeholder)} {/if} -{:else if captionLayout === 'dropdown-years'} +{:else if captionLayout === "dropdown-years"} {#if placeholder} {formatMonth(placeholder)} {/if} diff --git a/src/lib/components/ui/calendar/calendar-cell.svelte b/src/lib/components/ui/calendar/calendar-cell.svelte index 6eb8149..5f295d6 100644 --- a/src/lib/components/ui/calendar/calendar-cell.svelte +++ b/src/lib/components/ui/calendar/calendar-cell.svelte @@ -1,6 +1,6 @@ - + diff --git a/src/lib/components/ui/calendar/calendar-grid.svelte b/src/lib/components/ui/calendar/calendar-grid.svelte index bfa49dc..e0c8627 100644 --- a/src/lib/components/ui/calendar/calendar-grid.svelte +++ b/src/lib/components/ui/calendar/calendar-grid.svelte @@ -1,6 +1,6 @@ -
+
{@render children?.()}
diff --git a/src/lib/components/ui/calendar/calendar-months.svelte b/src/lib/components/ui/calendar/calendar-months.svelte index 023cad3..f717a9d 100644 --- a/src/lib/components/ui/calendar/calendar-months.svelte +++ b/src/lib/components/ui/calendar/calendar-months.svelte @@ -1,6 +1,6 @@ @@ -50,7 +50,7 @@ get along, so we shut typescript up by casting `value` to `never`. {weekdayFormat} {disableDaysOutsideMonth} class={cn( - 'bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent', + "bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent", className )} {locale} @@ -97,7 +97,7 @@ get along, so we shut typescript up by casting `value` to `never`. {#if day} {@render day({ day: date, - outsideMonth: !isEqualMonth(date, month.value) + outsideMonth: !isEqualMonth(date, month.value), })} {:else} diff --git a/src/lib/components/ui/calendar/index.ts b/src/lib/components/ui/calendar/index.ts index 180d173..f3a16d2 100644 --- a/src/lib/components/ui/calendar/index.ts +++ b/src/lib/components/ui/calendar/index.ts @@ -1,21 +1,21 @@ -import Root from './calendar.svelte'; -import Cell from './calendar-cell.svelte'; -import Day from './calendar-day.svelte'; -import Grid from './calendar-grid.svelte'; -import Header from './calendar-header.svelte'; -import Months from './calendar-months.svelte'; -import GridRow from './calendar-grid-row.svelte'; -import Heading from './calendar-heading.svelte'; -import GridBody from './calendar-grid-body.svelte'; -import GridHead from './calendar-grid-head.svelte'; -import HeadCell from './calendar-head-cell.svelte'; -import NextButton from './calendar-next-button.svelte'; -import PrevButton from './calendar-prev-button.svelte'; -import MonthSelect from './calendar-month-select.svelte'; -import YearSelect from './calendar-year-select.svelte'; -import Month from './calendar-month.svelte'; -import Nav from './calendar-nav.svelte'; -import Caption from './calendar-caption.svelte'; +import Root from "./calendar.svelte"; +import Cell from "./calendar-cell.svelte"; +import Day from "./calendar-day.svelte"; +import Grid from "./calendar-grid.svelte"; +import Header from "./calendar-header.svelte"; +import Months from "./calendar-months.svelte"; +import GridRow from "./calendar-grid-row.svelte"; +import Heading from "./calendar-heading.svelte"; +import GridBody from "./calendar-grid-body.svelte"; +import GridHead from "./calendar-grid-head.svelte"; +import HeadCell from "./calendar-head-cell.svelte"; +import NextButton from "./calendar-next-button.svelte"; +import PrevButton from "./calendar-prev-button.svelte"; +import MonthSelect from "./calendar-month-select.svelte"; +import YearSelect from "./calendar-year-select.svelte"; +import Month from "./calendar-month.svelte"; +import Nav from "./calendar-nav.svelte"; +import Caption from "./calendar-caption.svelte"; export { Day, @@ -36,5 +36,5 @@ export { MonthSelect, Caption, // - Root as Calendar + Root as Calendar, }; diff --git a/src/lib/components/ui/pagination/index.ts b/src/lib/components/ui/pagination/index.ts index 2f5532a..d83c7a9 100644 --- a/src/lib/components/ui/pagination/index.ts +++ b/src/lib/components/ui/pagination/index.ts @@ -1,10 +1,10 @@ -import Root from './pagination.svelte'; -import Content from './pagination-content.svelte'; -import Item from './pagination-item.svelte'; -import Link from './pagination-link.svelte'; -import PrevButton from './pagination-prev-button.svelte'; -import NextButton from './pagination-next-button.svelte'; -import Ellipsis from './pagination-ellipsis.svelte'; +import Root from "./pagination.svelte"; +import Content from "./pagination-content.svelte"; +import Item from "./pagination-item.svelte"; +import Link from "./pagination-link.svelte"; +import PrevButton from "./pagination-prev-button.svelte"; +import NextButton from "./pagination-next-button.svelte"; +import Ellipsis from "./pagination-ellipsis.svelte"; export { Root, @@ -21,5 +21,5 @@ export { Link as PaginationLink, PrevButton as PaginationPrevButton, NextButton as PaginationNextButton, - Ellipsis as PaginationEllipsis + Ellipsis as PaginationEllipsis, }; diff --git a/src/lib/components/ui/pagination/pagination-content.svelte b/src/lib/components/ui/pagination/pagination-content.svelte index ce650ce..e1124fc 100644 --- a/src/lib/components/ui/pagination/pagination-content.svelte +++ b/src/lib/components/ui/pagination/pagination-content.svelte @@ -1,6 +1,6 @@ + + + {#if data.bracket.scheduling_mode === SchedulingMode.single} + + {:else if data.bracket.scheduling_mode === SchedulingMode.double} + double + {:else if data.bracket.scheduling_mode === SchedulingMode.round_robin} + round_robin + {:else if data.bracket.scheduling_mode === SchedulingMode.swiss} + swiss + {:else if data.bracket.scheduling_mode === SchedulingMode.double_round_robin} + double_round_robin + {/if} + diff --git a/src/routes/competitions/[id]/rounds/[round_id]/+page.svelte b/src/routes/competitions/[id]/rounds/[round_id]/+page.svelte deleted file mode 100644 index 491807b..0000000 --- a/src/routes/competitions/[id]/rounds/[round_id]/+page.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -{JSON.stringify(data)} diff --git a/src/routes/competitions/new/+page.svelte b/src/routes/competitions/new/+page.svelte index ed1311b..2af1744 100644 --- a/src/routes/competitions/new/+page.svelte +++ b/src/routes/competitions/new/+page.svelte @@ -1,8 +1,5 @@ -
-
-
-
- + + Create Competition | FlbxCup + + + +
+
+
+
+ +
+

Create New Competition

+

Set up your tournament and start competing

-

Create New Competition

-

Set up your tournament and start competing

-
- - - - - Competition Details - - Fill in the information below to create your competition - - -
-
- -
- - + + + + Competition Details + + Fill in the information below to create your competition + + + +
+ +
+ + + {#if errors.name} +

{errors.name}

+ {/if} +
+ + +
+ +
+ +
+ {#if errors.start_date} +

{errors.start_date}

+ {/if} +
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+ {#if errors.max_number_teams} +

{errors.max_number_teams}

+ {/if} +
+
+ + +
+ +