should've done this a while ago
24
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
3
.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||||
|
}
|
||||||
7
README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Tauri + React + Typescript
|
||||||
|
|
||||||
|
This template should help get you started developing with Tauri, React and Typescript in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||||
381
bun.lock
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "humanity-box-client",
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^1",
|
||||||
|
"bson": "^6.10.3",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-router": "^7.2.0",
|
||||||
|
"react-use-websocket": "^4.13.0",
|
||||||
|
"sass": "^1.85.1",
|
||||||
|
"uuid": "^11.1.0",
|
||||||
|
"vite-plugin-top-level-await": "^1.5.0",
|
||||||
|
"zustand": "^5.0.3",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tauri-apps/cli": "^1",
|
||||||
|
"@types/react": "^18.3.1",
|
||||||
|
"@types/react-dom": "^18.3.1",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"vite": "^6.0.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||||
|
|
||||||
|
"@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
|
||||||
|
|
||||||
|
"@babel/compat-data": ["@babel/compat-data@7.26.8", "", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="],
|
||||||
|
|
||||||
|
"@babel/core": ["@babel/core@7.26.9", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.9", "@babel/types": "^7.26.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw=="],
|
||||||
|
|
||||||
|
"@babel/generator": ["@babel/generator@7.26.9", "", { "dependencies": { "@babel/parser": "^7.26.9", "@babel/types": "^7.26.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.26.5", "", { "dependencies": { "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw=="],
|
||||||
|
|
||||||
|
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.26.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw=="],
|
||||||
|
|
||||||
|
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
|
||||||
|
|
||||||
|
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.25.9", "", {}, "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw=="],
|
||||||
|
|
||||||
|
"@babel/helpers": ["@babel/helpers@7.26.9", "", { "dependencies": { "@babel/template": "^7.26.9", "@babel/types": "^7.26.9" } }, "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA=="],
|
||||||
|
|
||||||
|
"@babel/parser": ["@babel/parser@7.26.9", "", { "dependencies": { "@babel/types": "^7.26.9" }, "bin": "./bin/babel-parser.js" }, "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A=="],
|
||||||
|
|
||||||
|
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="],
|
||||||
|
|
||||||
|
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="],
|
||||||
|
|
||||||
|
"@babel/template": ["@babel/template@7.26.9", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.26.9", "@babel/types": "^7.26.9" } }, "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA=="],
|
||||||
|
|
||||||
|
"@babel/traverse": ["@babel/traverse@7.26.9", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/types": "^7.26.9", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg=="],
|
||||||
|
|
||||||
|
"@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="],
|
||||||
|
|
||||||
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.0", "", { "os": "android", "cpu": "arm" }, "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.0", "", { "os": "android", "cpu": "arm64" }, "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g=="],
|
||||||
|
|
||||||
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.0", "", { "os": "android", "cpu": "x64" }, "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.0", "", { "os": "none", "cpu": "arm64" }, "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.0", "", { "os": "none", "cpu": "x64" }, "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg=="],
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ=="],
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
|
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||||
|
|
||||||
|
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="],
|
||||||
|
|
||||||
|
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
|
||||||
|
|
||||||
|
"@rollup/plugin-virtual": ["@rollup/plugin-virtual@3.0.2", "", { "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.9", "", { "os": "android", "cpu": "arm" }, "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.9", "", { "os": "android", "cpu": "arm64" }, "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w=="],
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.9", "", { "os": "win32", "cpu": "x64" }, "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw=="],
|
||||||
|
|
||||||
|
"@swc/core": ["@swc/core@1.11.7", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.19" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.11.7", "@swc/core-darwin-x64": "1.11.7", "@swc/core-linux-arm-gnueabihf": "1.11.7", "@swc/core-linux-arm64-gnu": "1.11.7", "@swc/core-linux-arm64-musl": "1.11.7", "@swc/core-linux-x64-gnu": "1.11.7", "@swc/core-linux-x64-musl": "1.11.7", "@swc/core-win32-arm64-msvc": "1.11.7", "@swc/core-win32-ia32-msvc": "1.11.7", "@swc/core-win32-x64-msvc": "1.11.7" }, "peerDependencies": { "@swc/helpers": "*" }, "optionalPeers": ["@swc/helpers"] }, "sha512-ICuzjyfz8Hh3U16Mb21uCRJeJd/lUgV999GjgvPhJSISM1L8GDSB5/AMNcwuGs7gFywTKI4vAeeXWyCETUXHAg=="],
|
||||||
|
|
||||||
|
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.11.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3+LhCP2H50CLI6yv/lhOtoZ5B/hi7Q/23dye1KhbSDeDprLTm/KfLJh/iQqwaHUponf5m8C2U0y6DD+HGLz8Yw=="],
|
||||||
|
|
||||||
|
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.11.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-1diWpJqwX1XmOghf9ENFaeRaTtqLiqlZIW56RfOqmeZ7tPp3qS7VygWb9akptBsO5pEA5ZwNgSerD6AJlQcjAw=="],
|
||||||
|
|
||||||
|
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.11.7", "", { "os": "linux", "cpu": "arm" }, "sha512-MV8+hLREf0NN23NuSKemsjFaWjl/HnqdOkE7uhXTnHzg8WTwp6ddVtU5Yriv15+d/ktfLWPVAOhLHQ4gzaoa8A=="],
|
||||||
|
|
||||||
|
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.11.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-5GNs8ZjHQy/UTSnzzn+gm1RCUpCYo43lsxYOl8mpcnZSfxkNFVpjfylBv0QuJ5qhdfZ2iU55+v4iJCwCMtw0nA=="],
|
||||||
|
|
||||||
|
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.11.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-cTydaYBwDbVV5CspwVcCp9IevYWpGD1cF5B5KlBdjmBzxxeWyTAJRtKzn8w5/UJe/MfdAptarpqMPIs2f33YEQ=="],
|
||||||
|
|
||||||
|
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.11.7", "", { "os": "linux", "cpu": "x64" }, "sha512-YAX2KfYPlbDsnZiVMI4ZwotF3VeURUrzD+emJgFf1g26F4eEmslldgnDrKybW7V+bObsH22cDqoy6jmQZgpuPQ=="],
|
||||||
|
|
||||||
|
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.11.7", "", { "os": "linux", "cpu": "x64" }, "sha512-mYT6FTDZyYx5pailc8xt6ClS2yjKmP8jNHxA9Ce3K21n5qkKilI5M2N7NShwXkd3Ksw3F29wKrg+wvEMXTRY/A=="],
|
||||||
|
|
||||||
|
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.11.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-uLDQEcv0BHcepypstyxKkNsW6KfLyI5jVxTbcxka+B2UnMcFpvoR87nGt2JYW0grO2SNZPoFz+UnoKL9c6JxpA=="],
|
||||||
|
|
||||||
|
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.11.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-wiq5G3fRizdxAJVFcon7zpyfbfrb+YShuTy+TqJ4Nf5PC0ueMOXmsmeuyQGApn6dVWtGCyymYQYt77wHeQajdA=="],
|
||||||
|
|
||||||
|
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.11.7", "", { "os": "win32", "cpu": "x64" }, "sha512-/zQdqY4fHkSORxEJ2cKtRBOwglvf/8gs6Tl4Q6VMx2zFtFpIOwFQstfY5u8wBNN2Z+PkAzyUCPoi8/cQFK8HLQ=="],
|
||||||
|
|
||||||
|
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
|
||||||
|
|
||||||
|
"@swc/types": ["@swc/types@0.1.19", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA=="],
|
||||||
|
|
||||||
|
"@tauri-apps/api": ["@tauri-apps/api@1.6.0", "", {}, "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli": ["@tauri-apps/cli@1.6.3", "", { "dependencies": { "semver": ">=7.5.2" }, "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "1.6.3", "@tauri-apps/cli-darwin-x64": "1.6.3", "@tauri-apps/cli-linux-arm-gnueabihf": "1.6.3", "@tauri-apps/cli-linux-arm64-gnu": "1.6.3", "@tauri-apps/cli-linux-arm64-musl": "1.6.3", "@tauri-apps/cli-linux-x64-gnu": "1.6.3", "@tauri-apps/cli-linux-x64-musl": "1.6.3", "@tauri-apps/cli-win32-arm64-msvc": "1.6.3", "@tauri-apps/cli-win32-ia32-msvc": "1.6.3", "@tauri-apps/cli-win32-x64-msvc": "1.6.3" }, "bin": { "tauri": "tauri.js" } }, "sha512-q46umd6QLRKDd4Gg6WyZBGa2fWvk0pbeUA5vFomm4uOs1/17LIciHv2iQ4UD+2Yv5H7AO8YiE1t50V0POiEGEw=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@1.6.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fQN6IYSL8bG4NvkdKE4sAGF4dF/QqqQq4hOAU+t8ksOzHJr0hUlJYfncFeJYutr/MMkdF7hYKadSb0j5EE9r0A=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@1.6.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-1yTXZzLajKAYINJOJhZfmMhCzweHSgKQ3bEgJSn6t+1vFkOgY8Yx4oFgWcybrrWI5J1ZLZAl47+LPOY81dLcyA=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@1.6.3", "", { "os": "linux", "cpu": "arm" }, "sha512-CjTEr9r9xgjcvos09AQw8QMRPuH152B1jvlZt4PfAsyJNPFigzuwed5/SF7XAd8bFikA7zArP4UT12RdBxrx7w=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@1.6.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-G9EUUS4M8M/Jz1UKZqvJmQQCKOzgTb8/0jZKvfBuGfh5AjFBu8LHvlFpwkKVm1l4951Xg4ulUp6P9Q7WRJ9XSA=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@1.6.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-MuBTHJyNpZRbPVG8IZBN8+Zs7aKqwD22tkWVBcL1yOGL4zNNTJlkfL+zs5qxRnHlUsn6YAlbW/5HKocfpxVwBw=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@1.6.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Uvi7M+NK3tAjCZEY1WGel+dFlzJmqcvu3KND+nqa22762NFmOuBIZ4KJR/IQHfpEYqKFNUhJfCGnpUDfiC3Oxg=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@1.6.3", "", { "os": "linux", "cpu": "x64" }, "sha512-rc6B342C0ra8VezB/OJom9j/N+9oW4VRA4qMxS2f4bHY2B/z3J9NPOe6GOILeg4v/CV62ojkLsC3/K/CeF3fqQ=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@1.6.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-cSH2qOBYuYC4UVIFtrc1YsGfc5tfYrotoHrpTvRjUGu0VywvmyNk82+ZsHEnWZ2UHmu3l3lXIGRqSWveLln0xg=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@1.6.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-T8V6SJQqE4PSWmYBl0ChQVmS6AR2hXFHURH2DwAhgSGSQ6uBXgwlYFcfIeQpBQA727K2Eq8X2hGfvmoySyHMRw=="],
|
||||||
|
|
||||||
|
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@1.6.3", "", { "os": "win32", "cpu": "x64" }, "sha512-HUkWZ+lYHI/Gjkh2QjHD/OBDpqLVmvjZGpLK9losur1Eg974Jip6k+vsoTUxQBCBDfj30eDBct9E1FvXOspWeg=="],
|
||||||
|
|
||||||
|
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||||
|
|
||||||
|
"@types/babel__generator": ["@types/babel__generator@7.6.8", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw=="],
|
||||||
|
|
||||||
|
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
|
||||||
|
|
||||||
|
"@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="],
|
||||||
|
|
||||||
|
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
|
||||||
|
|
||||||
|
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
|
||||||
|
|
||||||
|
"@types/prop-types": ["@types/prop-types@15.7.14", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@18.3.18", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ=="],
|
||||||
|
|
||||||
|
"@types/react-dom": ["@types/react-dom@18.3.5", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q=="],
|
||||||
|
|
||||||
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
|
||||||
|
|
||||||
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
|
"browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
|
||||||
|
|
||||||
|
"bson": ["bson@6.10.3", "", {}, "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ=="],
|
||||||
|
|
||||||
|
"caniuse-lite": ["caniuse-lite@1.0.30001702", "", {}, "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA=="],
|
||||||
|
|
||||||
|
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
|
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||||
|
|
||||||
|
"detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
|
||||||
|
|
||||||
|
"electron-to-chromium": ["electron-to-chromium@1.5.112", "", {}, "sha512-oen93kVyqSb3l+ziUgzIOlWt/oOuy4zRmpwestMn4rhFWAoFJeFuCVte9F2fASjeZZo7l/Cif9TiyrdW4CwEMA=="],
|
||||||
|
|
||||||
|
"esbuild": ["esbuild@0.25.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.0", "@esbuild/android-arm": "0.25.0", "@esbuild/android-arm64": "0.25.0", "@esbuild/android-x64": "0.25.0", "@esbuild/darwin-arm64": "0.25.0", "@esbuild/darwin-x64": "0.25.0", "@esbuild/freebsd-arm64": "0.25.0", "@esbuild/freebsd-x64": "0.25.0", "@esbuild/linux-arm": "0.25.0", "@esbuild/linux-arm64": "0.25.0", "@esbuild/linux-ia32": "0.25.0", "@esbuild/linux-loong64": "0.25.0", "@esbuild/linux-mips64el": "0.25.0", "@esbuild/linux-ppc64": "0.25.0", "@esbuild/linux-riscv64": "0.25.0", "@esbuild/linux-s390x": "0.25.0", "@esbuild/linux-x64": "0.25.0", "@esbuild/netbsd-arm64": "0.25.0", "@esbuild/netbsd-x64": "0.25.0", "@esbuild/openbsd-arm64": "0.25.0", "@esbuild/openbsd-x64": "0.25.0", "@esbuild/sunos-x64": "0.25.0", "@esbuild/win32-arm64": "0.25.0", "@esbuild/win32-ia32": "0.25.0", "@esbuild/win32-x64": "0.25.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw=="],
|
||||||
|
|
||||||
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
|
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||||
|
|
||||||
|
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||||
|
|
||||||
|
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||||
|
|
||||||
|
"immutable": ["immutable@5.0.3", "", {}, "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw=="],
|
||||||
|
|
||||||
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|
||||||
|
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||||
|
|
||||||
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
||||||
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
|
|
||||||
|
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||||
|
|
||||||
|
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||||
|
|
||||||
|
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
||||||
|
|
||||||
|
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||||
|
|
||||||
|
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
||||||
|
|
||||||
|
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
||||||
|
|
||||||
|
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||||
|
|
||||||
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||||
|
|
||||||
|
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
|
||||||
|
|
||||||
|
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
|
||||||
|
|
||||||
|
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
|
||||||
|
|
||||||
|
"react-router": ["react-router@7.2.0", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0", "turbo-stream": "2.4.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ=="],
|
||||||
|
|
||||||
|
"react-use-websocket": ["react-use-websocket@4.13.0", "", {}, "sha512-anMuVoV//g2N76Wxqvqjjo1X48r9Np3y1/gMl7arX84tAPXdy5R7sB5lO5hvCzQRYjqXwV8XMAiEBOUbyrZFrw=="],
|
||||||
|
|
||||||
|
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
|
"rollup": ["rollup@4.34.9", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.9", "@rollup/rollup-android-arm64": "4.34.9", "@rollup/rollup-darwin-arm64": "4.34.9", "@rollup/rollup-darwin-x64": "4.34.9", "@rollup/rollup-freebsd-arm64": "4.34.9", "@rollup/rollup-freebsd-x64": "4.34.9", "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", "@rollup/rollup-linux-arm-musleabihf": "4.34.9", "@rollup/rollup-linux-arm64-gnu": "4.34.9", "@rollup/rollup-linux-arm64-musl": "4.34.9", "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", "@rollup/rollup-linux-riscv64-gnu": "4.34.9", "@rollup/rollup-linux-s390x-gnu": "4.34.9", "@rollup/rollup-linux-x64-gnu": "4.34.9", "@rollup/rollup-linux-x64-musl": "4.34.9", "@rollup/rollup-win32-arm64-msvc": "4.34.9", "@rollup/rollup-win32-ia32-msvc": "4.34.9", "@rollup/rollup-win32-x64-msvc": "4.34.9", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ=="],
|
||||||
|
|
||||||
|
"sass": ["sass@1.85.1", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-Uk8WpxM5v+0cMR0XjX9KfRIacmSG86RH4DCCZjLU2rFh5tyutt9siAXJ7G+YfxQ99Q6wrRMbMlVl6KqUms71ag=="],
|
||||||
|
|
||||||
|
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
||||||
|
|
||||||
|
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||||
|
|
||||||
|
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
|
||||||
|
|
||||||
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
|
"turbo-stream": ["turbo-stream@2.4.0", "", {}, "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
||||||
|
|
||||||
|
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
|
||||||
|
|
||||||
|
"uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
|
||||||
|
|
||||||
|
"vite": ["vite@6.2.0", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ=="],
|
||||||
|
|
||||||
|
"vite-plugin-top-level-await": ["vite-plugin-top-level-await@1.5.0", "", { "dependencies": { "@rollup/plugin-virtual": "^3.0.2", "@swc/core": "^1.10.16", "uuid": "^10.0.0" }, "peerDependencies": { "vite": ">=2.8" } }, "sha512-r/DtuvHrSqUVk23XpG2cl8gjt1aATMG5cjExXL1BUTcSNab6CzkcPua9BPEc9fuTP5UpwClCxUe3+dNGL0yrgQ=="],
|
||||||
|
|
||||||
|
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||||
|
|
||||||
|
"zustand": ["zustand@5.0.3", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg=="],
|
||||||
|
|
||||||
|
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
|
"vite-plugin-top-level-await/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
14
index.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Tauri + React + Typescript</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
32
package.json
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "humanity-box-client",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"tauri": "tauri"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^1",
|
||||||
|
"bson": "^6.10.3",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-router": "^7.2.0",
|
||||||
|
"react-use-websocket": "^4.13.0",
|
||||||
|
"sass": "^1.85.1",
|
||||||
|
"uuid": "^11.1.0",
|
||||||
|
"vite-plugin-top-level-await": "^1.5.0",
|
||||||
|
"zustand": "^5.0.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.3.1",
|
||||||
|
"@types/react-dom": "^18.3.1",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"vite": "^6.0.3",
|
||||||
|
"@tauri-apps/cli": "^1"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/assets/sounds/game_music.mp3
Normal file
6
public/tauri.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
|
||||||
|
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
1
public/vite.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
7
src-tauri/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Generated by Tauri
|
||||||
|
# will have schema files for capabilities auto-completion
|
||||||
|
/gen/schemas
|
||||||
4053
src-tauri/Cargo.lock
generated
Normal file
20
src-tauri/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "humanity-box-client"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A Tauri App"
|
||||||
|
authors = ["you"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tauri-build = { version = "1", features = [] }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tauri = { version = "1", features = ["shell-open"] }
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
|
||||||
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
3
src-tauri/build.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
tauri_build::build()
|
||||||
|
}
|
||||||
BIN
src-tauri/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 974 B |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
|
After Width: | Height: | Size: 903 B |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
src-tauri/icons/icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
17
src-tauri/src/main.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
|
// Learn more about Tauri commands at https://v1.tauri.app/v1/guides/features/command
|
||||||
|
#[tauri::command]
|
||||||
|
fn game_quit_application(app_handle: tauri::AppHandle) {
|
||||||
|
app_handle.get_focused_window().unwrap().close().expect("Failed to close window. Why???");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
tauri::Builder::default()
|
||||||
|
.invoke_handler(tauri::generate_handler![game_quit_application])
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
||||||
46
src-tauri/tauri.conf.json
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://schema.tauri.app/config/1",
|
||||||
|
"build": {
|
||||||
|
"beforeDevCommand": "bun run dev",
|
||||||
|
"beforeBuildCommand": "bun run build",
|
||||||
|
"devPath": "http://localhost:1420",
|
||||||
|
"distDir": "../dist"
|
||||||
|
},
|
||||||
|
"package": {
|
||||||
|
"productName": "humanity-box-client",
|
||||||
|
"version": "0.1.0"
|
||||||
|
},
|
||||||
|
"tauri": {
|
||||||
|
"allowlist": {
|
||||||
|
"all": false,
|
||||||
|
"shell": {
|
||||||
|
"all": false,
|
||||||
|
"open": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"title": "Inhumane",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 720,
|
||||||
|
"fullscreen": true,
|
||||||
|
"additionalBrowserArgs": "autoplay-policy=no-user-gesture-required"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": {
|
||||||
|
"csp": null
|
||||||
|
},
|
||||||
|
"bundle": {
|
||||||
|
"active": true,
|
||||||
|
"targets": "all",
|
||||||
|
"identifier": "com.neo.humanity-box.client",
|
||||||
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/App.scss
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
line-height: 1.2;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
|
||||||
|
--default-card-font-size: 1.6rem;
|
||||||
|
--default-sizable-card-size: 13.75rem;
|
||||||
|
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: hsla(0, 0%, 14%, 1);
|
||||||
|
|
||||||
|
background: linear-gradient(125deg, lch(14.2% 0 139.09) 0%, lch(0% 0 0) 100%);
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
user-select: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 1920px;
|
||||||
|
height: 1080px;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: -960px;
|
||||||
|
margin-top: -540px;
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
48
src/App.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import "./App.scss"
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import HumanityBoxHome from "./game/HumanityBoxHome.tsx";
|
||||||
|
import {GameMusic, soundManager} from "./utilities/SoundManager.ts";
|
||||||
|
import {getUserSetting, loadUserSettings} from "./UserSettings.ts";
|
||||||
|
import {BrowserRouter, Route, Routes} from "react-router";
|
||||||
|
import {HumanityBoxGame} from "./game/HumanityBoxGame.tsx";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
|
||||||
|
async function loadMainMusic() {
|
||||||
|
GameMusic.play();
|
||||||
|
GameMusic.setVolume(getUserSetting("MusicVolume"))
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadUserSettings();
|
||||||
|
|
||||||
|
function resizeListener() {
|
||||||
|
|
||||||
|
let heightScale = (window.innerWidth - 24) / 1920
|
||||||
|
let widthScale = (window.innerHeight - 24) / 1080
|
||||||
|
|
||||||
|
document.body.style.transform = `scale(${Math.min(heightScale, widthScale)})`
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", resizeListener);
|
||||||
|
|
||||||
|
resizeListener();
|
||||||
|
|
||||||
|
loadMainMusic().then();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", resizeListener);
|
||||||
|
soundManager.getContext()!.close()
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route path={"/"} element={<HumanityBoxHome />} />
|
||||||
|
<Route path={"/start-game"} element={<HumanityBoxGame />} />
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
35
src/UserSettings.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
export interface UserSettings {
|
||||||
|
MusicVolume: number,
|
||||||
|
GlobalVolume: number,
|
||||||
|
MaxPlayers: number,
|
||||||
|
PointsToWin: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
let internalState: UserSettings = {
|
||||||
|
MusicVolume: 0.6,
|
||||||
|
GlobalVolume: 1,
|
||||||
|
MaxPlayers: 8,
|
||||||
|
PointsToWin: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUserSetting<K extends keyof UserSettings>(setting: K, value: UserSettings[K]) {
|
||||||
|
internalState[setting] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserSetting<K extends keyof UserSettings>(setting: K): UserSettings[K] {
|
||||||
|
return internalState[setting]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveUserSettings() {
|
||||||
|
localStorage.setItem("user-preferences", JSON.stringify(internalState))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadUserSettings(): void {
|
||||||
|
if (localStorage.getItem("user-preferences") != null) {
|
||||||
|
let settings = (JSON.parse(localStorage.getItem("user-preferences") ?? "{}") as UserSettings)
|
||||||
|
for (const key of Object.keys(settings)) {
|
||||||
|
// @ts-ignore
|
||||||
|
internalState[key] = settings[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/assets/react.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
12
src/components/Hooks.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
export const useProperty = (on: HTMLElement, property: string) => {
|
||||||
|
return window.getComputedStyle(on).getPropertyValue(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTextWidth = (el: HTMLElement, text: string) => {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const context = canvas.getContext('2d')!;
|
||||||
|
|
||||||
|
context.font = getComputedStyle(el).font;
|
||||||
|
|
||||||
|
return context.measureText(text).width;
|
||||||
|
}
|
||||||
4
src/components/cards/PlayerCard.module.scss
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.player-card {
|
||||||
|
aspect-ratio: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
21
src/components/cards/PlayerCard.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import SizableCard, {CardSize} from "./SizableCard.tsx";
|
||||||
|
import s from "./PlayerCard.module.scss"
|
||||||
|
|
||||||
|
type PlayerCardProps = {
|
||||||
|
size: keyof typeof CardSize,
|
||||||
|
name: string,
|
||||||
|
color: "black" | "white",
|
||||||
|
onClick?: () => void,
|
||||||
|
className?: string,
|
||||||
|
points?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlayerCard({ size, name, color, onClick, className, points}: PlayerCardProps) {
|
||||||
|
return <SizableCard
|
||||||
|
size={size}
|
||||||
|
content={name}
|
||||||
|
color={color}
|
||||||
|
onClick={onClick}
|
||||||
|
player={points ? `${points} points` : undefined}
|
||||||
|
className={[s["player-card"], className].join(" ")} />
|
||||||
|
}
|
||||||
44
src/components/cards/SizableCard.module.scss
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
.sizable-card {
|
||||||
|
width: calc(var(--default-sizable-card-size) * var(--sizable-card-scale));
|
||||||
|
font-size: calc(var(--default-card-font-size) * var(--sizable-card-font-scale));
|
||||||
|
aspect-ratio: 2 / 3;
|
||||||
|
border-radius: calc(1.2rem * var(--sizable-card-scale));
|
||||||
|
box-shadow: 0px 1px 8px -2px rgba(255, 255, 255, 0.1);
|
||||||
|
font-weight: 900;
|
||||||
|
padding: calc(1.2rem * var(--sizable-card-scale)) calc(1.35rem * var(--sizable-card-scale));
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&[data-cardcolor="black"] {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-cardcolor="white"] {
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-section {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
gap: .4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-label {
|
||||||
|
font-size: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-name {
|
||||||
|
width: 100%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: .5em;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/components/cards/SizableCard.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import {createRef, CSSProperties, useEffect, useState} from "react";
|
||||||
|
import s from "./SizableCard.module.scss"
|
||||||
|
|
||||||
|
export const CardSize = {
|
||||||
|
sm: 0.3,
|
||||||
|
md: 0.5,
|
||||||
|
nm: 0.7,
|
||||||
|
lg: 0.8,
|
||||||
|
xl: 0.9
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SizableCardProps = {
|
||||||
|
size: keyof typeof CardSize,
|
||||||
|
content: string,
|
||||||
|
color: "black" | "white",
|
||||||
|
player?: string,
|
||||||
|
obfuscatePlayer?: boolean,
|
||||||
|
onClick?: () => void,
|
||||||
|
className?: string,
|
||||||
|
style?: CSSProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SizableCard({ size, content, color, player, obfuscatePlayer, onClick, className, style }: SizableCardProps) {
|
||||||
|
const [cardScale, setCardScale] = useState(1);
|
||||||
|
const [fontScale, setFontScale] = useState(1);
|
||||||
|
const cardRef = createRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
setCardScale(CardSize[size]);
|
||||||
|
|
||||||
|
}, [size]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFontScale(Math.max((-1/(Math.PI*120)*(content.replace("{{fill}}", "_____").length-40)+1), 0.5)*CardSize[size]);
|
||||||
|
}, [content, size]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div onClick={onClick} ref={cardRef} className={[s["sizable-card"], className].join(" ")} data-cardcolor={color} style={{
|
||||||
|
["--sizable-card-scale" as string]: cardScale,
|
||||||
|
["--sizable-card-font-scale" as string]: fontScale,
|
||||||
|
...style
|
||||||
|
}}>
|
||||||
|
<div className={s["card-content"]}>
|
||||||
|
{content.replace("{{fill}}", "_____")}
|
||||||
|
</div>
|
||||||
|
<div className={s["bottom-section"]}>
|
||||||
|
{player && (
|
||||||
|
<div className={s["player-name"]}>
|
||||||
|
{obfuscatePlayer ? "???" : player}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={s["card-label"]}>
|
||||||
|
Inhumane
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
85
src/game/ActionScreen.module.scss
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr max-content 1fr;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
|
||||||
|
.player-top-display {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-choosing-grid {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
gap: 1.5rem;
|
||||||
|
& > * {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
gap: 1.5rem;
|
||||||
|
grid-template-columns: repeat(4, max-content);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes popIn {
|
||||||
|
0% {
|
||||||
|
transforM: scale(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-player {
|
||||||
|
position: relative;
|
||||||
|
animation: popIn 600ms 1 forwards;
|
||||||
|
transform: scale(0);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "🤔";
|
||||||
|
position: absolute;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width:max-content;
|
||||||
|
left: -.6rem;
|
||||||
|
top: -1rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.what-to-do {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.played-cards {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
gap: 1.5rem;
|
||||||
|
height: max-content;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.played-card {
|
||||||
|
transform: scale(0);
|
||||||
|
animation: popIn 600ms var(--delay) 1 forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
55
src/game/ActionScreen.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import {PlayerCard} from "../components/cards/PlayerCard.tsx";
|
||||||
|
import SizableCard from "../components/cards/SizableCard.tsx";
|
||||||
|
import s from "./ActionScreen.module.scss"
|
||||||
|
import {useContext, useEffect} from "react";
|
||||||
|
import {GameContext, useGameState} from "./GameContext.ts";
|
||||||
|
|
||||||
|
export function ActionScreen() {
|
||||||
|
const { actionState, gameHeader} = useContext(GameContext)
|
||||||
|
|
||||||
|
const gameState = useGameState()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(gameState.winningPlayer)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s["container"]}>
|
||||||
|
<div className={s["top-container"]}>
|
||||||
|
<div className={s["player-top-display"]}>
|
||||||
|
<PlayerCard size={"xl"} name={"Faggot"} color={"black"}/>
|
||||||
|
<SizableCard size={"xl"} content={gameState.blackCard} color={"black"}/>
|
||||||
|
</div>
|
||||||
|
{actionState == "reveal-winner" && <div className={s["player-top-display"]}>
|
||||||
|
<PlayerCard size={"xl"} name={gameState.players.get(gameState.winningPlayer)!.name} color={"white"}/>
|
||||||
|
<SizableCard size={"xl"} content={gameState.playedWhiteCards.get(gameState.winningPlayer)!} color={"white"}/>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
<div className={s["what-to-do"]}>{gameHeader}</div>
|
||||||
|
{actionState == "selecting-cards" && <div className={s["player-choosing-grid"]}>
|
||||||
|
<div>
|
||||||
|
{gameState.getPlayers().slice(0, 4).map((player) => (
|
||||||
|
<div>
|
||||||
|
<PlayerCard className={player.isThinking ? s["thinking-player"] : ""} size={"nm"} name={player.name} color={"white"}/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{gameState.getPlayers().slice(4, 8).map((player) => (
|
||||||
|
<div>
|
||||||
|
<PlayerCard className={player.isThinking ? s["thinking-player"] : ""} size={"nm"} name={player.name} color={"white"}/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
{(actionState == "picking-card" || actionState == "reveal-winner" )&& <div className={s["played-cards"]}>
|
||||||
|
{[...gameState.playedWhiteCards.entries()].map(([userId, cardContent], i) => (
|
||||||
|
<SizableCard style={{
|
||||||
|
["--delay" as string]: `${150*i}ms`
|
||||||
|
}} className={s["played-card"]} size={"nm"} player={gameState.players.get(userId)!.name} obfuscatePlayer={actionState != "reveal-winner"} content={cardContent} color={"white"}/>
|
||||||
|
))}
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
42
src/game/ConnectionScreen.module.scss
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
.throbber {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width: 1.8rem;
|
||||||
|
stroke-dasharray: 25 75;
|
||||||
|
animation: throbberAnimate 1.2s linear infinite forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes throbberAnimate {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 25 75;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
stroke-dasharray: 90 10;
|
||||||
|
stroke-dashoffset: -25;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 50 50;
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 25 75;
|
||||||
|
stroke-dashoffset: -200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
14
src/game/ConnectionScreen.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import s from "./ConnectionScreen.module.scss";
|
||||||
|
|
||||||
|
export function ConnectionScreen() {
|
||||||
|
return (
|
||||||
|
<div className={s["container"]}>
|
||||||
|
<div className={s["connection-container"]}>
|
||||||
|
<div>Connecting...</div>
|
||||||
|
<svg className={s["throbber"]} viewBox={"0 0 100 100"} xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx={50} cy={50} r={45} strokeWidth={10} pathLength={100} strokeLinecap={"round"} stroke={"currentColor"} />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
66
src/game/GameContext.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import {createContext} from "react";
|
||||||
|
import {create} from "zustand";
|
||||||
|
|
||||||
|
export type ActionState = "selecting-cards" | "picking-card" | "reveal-winner" | "showing-black"
|
||||||
|
|
||||||
|
type Player = {
|
||||||
|
name: string,
|
||||||
|
uuid: string,
|
||||||
|
isThinking: boolean,
|
||||||
|
availableCards: string[],
|
||||||
|
points: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGameState = create(() => ({
|
||||||
|
players: new Map<string, Player>,
|
||||||
|
cardPicker: "",
|
||||||
|
blackCard: "",
|
||||||
|
playedWhiteCards: new Map<string, string>(),
|
||||||
|
winningPlayer: "",
|
||||||
|
vip: "",
|
||||||
|
decks: {
|
||||||
|
whites: [] as string[],
|
||||||
|
blacks: [] as string[]
|
||||||
|
},
|
||||||
|
|
||||||
|
getBlackCard() {
|
||||||
|
const card = this.decks.blacks[Math.floor(Math.random() * this.decks.blacks.length)];
|
||||||
|
this.decks.blacks = this.decks.blacks.filter(c => c != card)
|
||||||
|
return card
|
||||||
|
},
|
||||||
|
async fetchCards() {
|
||||||
|
const blacksRes = await fetch("http://localhost:8080/api/v1/pick-card/black")
|
||||||
|
this.decks.blacks = await blacksRes.json()
|
||||||
|
const whitesRes = await fetch("http://localhost:8080/api/v1/pick-card/white")
|
||||||
|
this.decks.whites = await whitesRes.json()
|
||||||
|
},
|
||||||
|
getWhiteCards(amount: number) {
|
||||||
|
let cards: string[] = []
|
||||||
|
for (let i = 0; i < amount; i++) {
|
||||||
|
const card = this.decks.whites[Math.floor(Math.random() * this.decks.whites.length)];
|
||||||
|
this.decks.whites = this.decks.whites.filter(c => c != card)
|
||||||
|
cards.push(card)
|
||||||
|
}
|
||||||
|
return cards
|
||||||
|
},
|
||||||
|
getPlayers() {
|
||||||
|
return [...this.players.values()]
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
type GameContextProps = {
|
||||||
|
gameCode?: string;
|
||||||
|
setGameCode: (gameCode?: string) => void;
|
||||||
|
actionState: ActionState,
|
||||||
|
setActionState: (state: ActionState) => void,
|
||||||
|
gameHeader: string,
|
||||||
|
setHeader: (header: string) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GameContext = createContext<GameContextProps>({
|
||||||
|
setGameCode: () => {},
|
||||||
|
setActionState: () => {},
|
||||||
|
actionState: "showing-black",
|
||||||
|
gameHeader: "",
|
||||||
|
setHeader: () => {},
|
||||||
|
});
|
||||||
87
src/game/HumanityBoxGame.module.scss
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
.game {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > *:not(.exit-container, .exit-box) {
|
||||||
|
transform: scale(0);
|
||||||
|
animation: popIn 800ms forwards;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit-container {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.exit-scale-container {
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit-box {
|
||||||
|
width: 24.5rem;
|
||||||
|
aspect-ratio: 1.8/1;
|
||||||
|
background-color: #efefefaa;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
color: black;
|
||||||
|
border-radius: .8rem;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
padding: 1.8rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
flex-flow: column;
|
||||||
|
transition: 300ms;
|
||||||
|
|
||||||
|
&[data-visible="false"] {
|
||||||
|
pointer-events: none;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-visible="true"] {
|
||||||
|
transform: scale(1);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
background-color: black;
|
||||||
|
border-radius: .8rem;
|
||||||
|
color: white;
|
||||||
|
padding: .6rem 1.6rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 300ms;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes popIn {
|
||||||
|
from {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
225
src/game/HumanityBoxGame.tsx
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
import s from "./HumanityBoxGame.module.scss"
|
||||||
|
import HumanityBoxGameCode from "./HumanityBoxGameCode.tsx";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import {useNavigate} from "react-router";
|
||||||
|
import {ActionState, GameContext, useGameState} from "./GameContext.ts";
|
||||||
|
import {ConnectionScreen} from "./ConnectionScreen.tsx";
|
||||||
|
import useWebSocket from "react-use-websocket";
|
||||||
|
import {BSON} from "bson";
|
||||||
|
import {handlePacket, handlers} from "./socketHandler.ts";
|
||||||
|
import { createPacket, GameSecretsCfg, GamePlayerJoin, GamePlayerLeave } from "../../../game-networking/src/types/socket.ts";
|
||||||
|
import {getUserSetting} from "../UserSettings.ts";
|
||||||
|
import {ActionScreen} from "./ActionScreen.tsx";
|
||||||
|
import {v4} from "uuid";
|
||||||
|
|
||||||
|
export function HumanityBoxGame() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [exitVisible, setExitVisible] = useState(false);
|
||||||
|
|
||||||
|
const gameState = useGameState();
|
||||||
|
|
||||||
|
handlers.clear()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function openCloseMenu(ev: KeyboardEvent) {
|
||||||
|
if (ev.code == "Escape") {
|
||||||
|
setExitVisible(true);
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("keydown", openCloseMenu);
|
||||||
|
|
||||||
|
return () => window.removeEventListener("keydown", openCloseMenu);
|
||||||
|
})
|
||||||
|
|
||||||
|
// game variables
|
||||||
|
|
||||||
|
const [gameCode, setGameCode] = useState<string>()
|
||||||
|
|
||||||
|
const [screenState, setScreenState] = useState("connecting")
|
||||||
|
const [actionState, setActionState] = useState<ActionState>("showing-black")
|
||||||
|
const [gameHeader, setGameHeader] = useState<string>("")
|
||||||
|
|
||||||
|
function ser(obj: any) {
|
||||||
|
return BSON.serialize(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.set("cfg.gameSecrets", async (data: GameSecretsCfg, send) => {
|
||||||
|
setGameCode(data.gameCode)
|
||||||
|
await gameState.fetchCards()
|
||||||
|
setTimeout(() => {
|
||||||
|
setScreenState("join-lobby")
|
||||||
|
}, 1200)
|
||||||
|
send(ser(createPacket("cfg.gameConnectionHash", {
|
||||||
|
hash: [...crypto.getRandomValues(new Uint8Array(16)).values()].map((v) => ((v * 2) % 255).toString(16)).join("")
|
||||||
|
})))
|
||||||
|
})
|
||||||
|
|
||||||
|
const [connRelationMap, setConnRelationMap] = useState<Map<string, string>>(new Map<string, string>())
|
||||||
|
|
||||||
|
handlers.set("game.playerJoin", (data: GamePlayerJoin, send, conn) => {
|
||||||
|
if (!conn) return;
|
||||||
|
|
||||||
|
if (gameState.players.size < getUserSetting("MaxPlayers")) {
|
||||||
|
const player = {
|
||||||
|
name: data.playerName,
|
||||||
|
uuid: v4(),
|
||||||
|
availableCards: gameState.getWhiteCards(7),
|
||||||
|
isThinking: false,
|
||||||
|
points: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
setConnRelationMap((relMap) => {
|
||||||
|
return new Map(relMap).set(conn, player.uuid)
|
||||||
|
})
|
||||||
|
|
||||||
|
useGameState.setState((state) => ({
|
||||||
|
players: new Map(state.players).set(player.uuid, player)
|
||||||
|
}))
|
||||||
|
|
||||||
|
send(ser(createPacket("game.playerJoin", player, conn)))
|
||||||
|
} else {
|
||||||
|
send(ser(createPacket("game.forceQuit", {
|
||||||
|
reason: "Too many players"
|
||||||
|
}, conn)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
handlers.set("game.playerLeave", (data: GamePlayerLeave, _, conn) => {
|
||||||
|
const uuid = connRelationMap.get(conn!)!
|
||||||
|
useGameState.setState((state) => {
|
||||||
|
let players = new Map(state.players)
|
||||||
|
players.delete(uuid)
|
||||||
|
state.players = players
|
||||||
|
if (state.vip == data.uuid) {
|
||||||
|
if (state.players.size > 0) {
|
||||||
|
state.vip = [...gameState.players.values()][0].uuid
|
||||||
|
} else {
|
||||||
|
state.vip = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {...state}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
handlers.set("game.action.playCard", (data: { cardValue: string }, _, conn) => {
|
||||||
|
if (!conn) return;
|
||||||
|
|
||||||
|
const uuid = connRelationMap.get(conn!)!
|
||||||
|
|
||||||
|
if (!gameState.players.get(uuid)!.availableCards.includes(data.cardValue)) {
|
||||||
|
console.log("player attempted to play card that they didn't have")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
useGameState.setState((state) => {
|
||||||
|
state.players.get(uuid)!.isThinking = false
|
||||||
|
state.playedWhiteCards.set(uuid, data.cardValue)
|
||||||
|
// TODO: Make this minus 1 or it wont ever go next. dev only
|
||||||
|
if (state.playedWhiteCards.size >= state.players.size) {
|
||||||
|
setActionState("picking-card")
|
||||||
|
}
|
||||||
|
return {...state}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
handlers.set("game.action.pickCard", (data: { uuid: string, picked: string }) => {
|
||||||
|
useGameState.setState((state) => {
|
||||||
|
state.winningPlayer = data.picked
|
||||||
|
state.players.get(data.uuid)!.points++
|
||||||
|
state.winningPlayer = ""
|
||||||
|
state.playedWhiteCards.clear()
|
||||||
|
setActionState("reveal-winner")
|
||||||
|
setTimeout(() => {
|
||||||
|
chooseBlackCardAndPicker()
|
||||||
|
}, 5000)
|
||||||
|
return {...state}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function chooseBlackCardAndPicker() {
|
||||||
|
setActionState("showing-black")
|
||||||
|
setGameHeader("")
|
||||||
|
|
||||||
|
useGameState.setState((state) => ({
|
||||||
|
blackCard: state.getBlackCard(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
beginSelectCardsScreen()
|
||||||
|
}, 4000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginSelectCardsScreen() {
|
||||||
|
setActionState("selecting-cards")
|
||||||
|
useGameState.setState((state) => {
|
||||||
|
state.players.forEach((player) => {
|
||||||
|
player.isThinking = true
|
||||||
|
})
|
||||||
|
return {...state}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.set("vip.startGame", () => {
|
||||||
|
if (gameState.players.size >= 1) {
|
||||||
|
setScreenState("action-screen")
|
||||||
|
chooseBlackCardAndPicker()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { sendMessage, lastMessage } = useWebSocket("http://localhost:8080/live/start-game", {
|
||||||
|
reconnectAttempts: 5,
|
||||||
|
retryOnError: true,
|
||||||
|
reconnectInterval: (lastAttemptNumber) => lastAttemptNumber * 6000
|
||||||
|
})
|
||||||
|
|
||||||
|
async function handleMessage(msg: MessageEvent | null) {
|
||||||
|
if (msg) {
|
||||||
|
let data = await (msg.data as Blob).arrayBuffer();
|
||||||
|
console.log(`Last Message Received:`, BSON.deserialize(new Uint8Array(data)));
|
||||||
|
handlePacket(BSON.deserialize(new Uint8Array(data)), sendMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleMessage(lastMessage)
|
||||||
|
}, [lastMessage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GameContext.Provider value={{
|
||||||
|
gameCode,
|
||||||
|
setGameCode,
|
||||||
|
actionState,
|
||||||
|
setActionState,
|
||||||
|
gameHeader,
|
||||||
|
setHeader: setGameHeader,
|
||||||
|
}}>
|
||||||
|
<div className={s["game"]}>
|
||||||
|
<div className={s["exit-container"]}>
|
||||||
|
<div className={s["exit-scale-container"]}>
|
||||||
|
<div className={s["exit-box"]} data-visible={exitVisible}>
|
||||||
|
<div className={s["container-title"]}>Are you sure you want to exit?</div>
|
||||||
|
<div className={s["exit-options"]}>
|
||||||
|
<div onClick={() => {
|
||||||
|
navigate("/");
|
||||||
|
}}>
|
||||||
|
Exit
|
||||||
|
</div>
|
||||||
|
<div onClick={() => {
|
||||||
|
setExitVisible(false);
|
||||||
|
}}>
|
||||||
|
Noo!!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{screenState == "join-lobby" && <HumanityBoxGameCode />}
|
||||||
|
{screenState == "action-screen" && <ActionScreen/>}
|
||||||
|
{screenState == "connecting" && <ConnectionScreen /> }
|
||||||
|
</div>
|
||||||
|
</GameContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
69
src/game/HumanityBoxGameCode.module.scss
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
.join-card {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-card {
|
||||||
|
height: min-content !important;
|
||||||
|
aspect-ratio: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "humanitybox.tv";
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
font-size: 8rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.players-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, min-content);
|
||||||
|
grid-template-rows: repeat(2, max-content);
|
||||||
|
grid-gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-flip {
|
||||||
|
animation: flipIn 800ms forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flipIn {
|
||||||
|
0% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/game/HumanityBoxGameCode.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import SizableCard from "../components/cards/SizableCard.tsx";
|
||||||
|
import s from "./HumanityBoxGameCode.module.scss"
|
||||||
|
import {useContext} from "react";
|
||||||
|
import {getUserSetting} from "../UserSettings.ts";
|
||||||
|
import {PlayerCard} from "../components/cards/PlayerCard.tsx";
|
||||||
|
import {GameContext, useGameState} from "./GameContext.ts";
|
||||||
|
|
||||||
|
export default function HumanityBoxGameCode() {
|
||||||
|
const gameState = useGameState();
|
||||||
|
const gameContext = useContext(GameContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s["container"]}>
|
||||||
|
<div className={s["title"]}>
|
||||||
|
Inhumane
|
||||||
|
</div>
|
||||||
|
<div className={s["code"]}>
|
||||||
|
{gameContext.gameCode}
|
||||||
|
</div>
|
||||||
|
<div className={s["grid-container"]}>
|
||||||
|
<div className={s["players-grid"]}>
|
||||||
|
{[...gameState.players.values()].map((p) => {
|
||||||
|
return <PlayerCard className={s["card-flip"]} size={"xl"} name={p.name} color={"white"}/>
|
||||||
|
})}
|
||||||
|
{new Array<boolean>(getUserSetting("MaxPlayers")).fill(false, 0, 8-gameState.players.size).map(() => {
|
||||||
|
return <SizableCard className={[s["join-card"], s["player-card"]].join(" ")} size={"xl"} content={"Join"} color={"white"}/>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
103
src/game/HumanityBoxHome.module.scss
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
.home {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
gap: 4rem;
|
||||||
|
|
||||||
|
& > *:not(.settings-container) {
|
||||||
|
transform: scale(0);
|
||||||
|
animation: popIn 800ms forwards;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-exiting="true"] {
|
||||||
|
.title-screen {
|
||||||
|
transform: translateY(-100vh);
|
||||||
|
}
|
||||||
|
.humanity-home-options {
|
||||||
|
& > * {
|
||||||
|
&:first-child {
|
||||||
|
transform: translateX(-100vw);
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
transform: translateY(200vh);
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
transform: translateX(100vw);
|
||||||
|
}
|
||||||
|
transition: 800ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes popIn {
|
||||||
|
from {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-screen {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 8rem;
|
||||||
|
font-weight: 900;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-duration: .8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.humanity-home-options {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
gap: 6rem;
|
||||||
|
padding: .75rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
&:first-child {
|
||||||
|
transform: rotate(-10deg);
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
transition: 300ms;
|
||||||
|
transition-property: transform;
|
||||||
|
cursor: pointer;
|
||||||
|
transform: scale(1);
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
.settings-box {
|
||||||
|
width: 75%;
|
||||||
|
height: 75%;
|
||||||
|
transition: transform 300ms;
|
||||||
|
|
||||||
|
&[data-visible="false"] {
|
||||||
|
transform: translateY(300vh);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-visible="true"] {
|
||||||
|
transform: translateY(0);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/game/HumanityBoxHome.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import SizableCard from "../components/cards/SizableCard.tsx";
|
||||||
|
import s from "./HumanityBoxHome.module.scss"
|
||||||
|
import {invoke} from "@tauri-apps/api";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {Settings} from "../popups/SettingsPopup.tsx";
|
||||||
|
import {useNavigate} from "react-router";
|
||||||
|
|
||||||
|
export default function HumanityBoxHome() {
|
||||||
|
const [settingsVisible, setSettingsVisible] = useState<boolean>(false)
|
||||||
|
const [exiting, setExiting] = useState<boolean>(false)
|
||||||
|
const navigate = useNavigate();
|
||||||
|
return (
|
||||||
|
<div className={s["home"]} data-exiting={exiting}>
|
||||||
|
<div className={s["settings-container"]}>
|
||||||
|
<div className={s["settings-box"]} data-visible={settingsVisible}>
|
||||||
|
<Settings onClose={() => setSettingsVisible(false)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s["title-screen"]}>
|
||||||
|
Inhumane
|
||||||
|
</div>
|
||||||
|
<div className={s["humanity-home-options"]}>
|
||||||
|
<SizableCard onClick={() => {
|
||||||
|
setSettingsVisible(true)
|
||||||
|
}} size={"nm"} content={"Settings"} color={"white"} />
|
||||||
|
<SizableCard onClick={() => {
|
||||||
|
setExiting(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate("/start-game")
|
||||||
|
}, 300)
|
||||||
|
}} size={"xl"} content={"Play"} color={"white"} />
|
||||||
|
<SizableCard size={"nm"} content={"Quit"} color={"white"} onClick={() => {
|
||||||
|
invoke("game_quit_application")
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
0
src/game/HumanityBoxPlayingScreen.ts
Normal file
19
src/game/socketHandler.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {SendMessage} from "react-use-websocket";
|
||||||
|
|
||||||
|
type HandlerFunc = (data: any, send: SendMessage, conn?: string) => void;
|
||||||
|
export const handlers: Map<string, HandlerFunc> = new Map()
|
||||||
|
|
||||||
|
type Packet = {
|
||||||
|
op?: string,
|
||||||
|
data?: object,
|
||||||
|
conn?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handlePacket(data: Packet, send: SendMessage) {
|
||||||
|
if (data.op && data.data) {
|
||||||
|
let handler: HandlerFunc | undefined;
|
||||||
|
if ((handler = handlers.get(data.op)) != undefined) {
|
||||||
|
handler(data.data, send, data.conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
|
<App />
|
||||||
|
);
|
||||||
|
|
||||||
|
document.title = "Inhumane"
|
||||||
106
src/popups/SettingsPopup.module.scss
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
.setting-slider-body {
|
||||||
|
background-color: #1c1c1c;
|
||||||
|
border: 1px solid white;
|
||||||
|
border-radius: .2rem;
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.settings-slider {
|
||||||
|
width: var(--setting-value);
|
||||||
|
background-color: #c5c5c5;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: .8rem;
|
||||||
|
height: 1rem;
|
||||||
|
right: 0;
|
||||||
|
background: white;
|
||||||
|
transition: transform 300ms;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 1);
|
||||||
|
border: solid 1px black;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
transform: translateX(50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-value {
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.labeled-setting {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
gap: .6rem;
|
||||||
|
padding: 0 1.8rem;
|
||||||
|
.label {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
gap: .8rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-value {
|
||||||
|
min-width: 8rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
gap: 1.8rem;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
border-radius: 1rem;
|
||||||
|
position: relative;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
overflow-y: scroll;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-title {
|
||||||
|
font-size: 3rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 2rem;
|
||||||
|
right: 2rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-input {
|
||||||
|
font-size: 2.4rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #1c1c1caa;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
136
src/popups/SettingsPopup.tsx
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
import {createRef, useEffect, useState} from "react"
|
||||||
|
import s from "./SettingsPopup.module.scss"
|
||||||
|
import {getUserSetting, loadUserSettings, saveUserSettings, setUserSetting} from "../UserSettings.ts";
|
||||||
|
import {GameMusic, soundManager} from "../utilities/SoundManager.ts";
|
||||||
|
|
||||||
|
function SettingSlider({ value, onValueChange }: { value: number, onValueChange?: (value: number) => void }) {
|
||||||
|
const ref = createRef<HTMLDivElement>()
|
||||||
|
const [mouseDown, setMouseDown] = useState(false)
|
||||||
|
const [currentValue, setCurrentValue] = useState(value)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentValue(value)
|
||||||
|
}, [value])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s["setting-slider-body"]} ref={ref} onMouseMove={(ev) => {
|
||||||
|
if (!mouseDown) return
|
||||||
|
const box = ref.current!.getBoundingClientRect()!
|
||||||
|
setCurrentValue((ev.clientX - box.x) / box.width)
|
||||||
|
onValueChange?.call(null, currentValue)
|
||||||
|
}} onMouseDown={() => {
|
||||||
|
setMouseDown(true)
|
||||||
|
}} onClick={(ev) => {
|
||||||
|
const box = ref.current!.getBoundingClientRect()!
|
||||||
|
let val = (ev.clientX - box.x) / box.width
|
||||||
|
setCurrentValue(val!)
|
||||||
|
onValueChange?.call(null, val!)
|
||||||
|
}} onMouseUp={() => {
|
||||||
|
setMouseDown(false)
|
||||||
|
}} onMouseLeave={() => {
|
||||||
|
setMouseDown(false)
|
||||||
|
}}>
|
||||||
|
<div className={s["settings-slider"]} style={{
|
||||||
|
["--setting-value" as string]: `${Math.min(100, Math.max(0, currentValue * 100))}%`
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Setting({label, children}: { label: string, children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<div className={s["labeled-setting"]}>
|
||||||
|
<div className={s["label"]}>{label}</div>
|
||||||
|
<div className={s["value"]}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Settings({ onClose }: { onClose?: () => void }) {
|
||||||
|
loadUserSettings()
|
||||||
|
const [musicVolume, setMusicVolume] = useState(getUserSetting("MusicVolume"))
|
||||||
|
const [globalVolume, setGlobalVolume] = useState(getUserSetting("GlobalVolume"))
|
||||||
|
const [maxPlayers, setMaxPlayers] = useState<string>(getUserSetting("MaxPlayers").toString())
|
||||||
|
const [pointsToWin, setPointsToWin] = useState<string>(getUserSetting("PointsToWin").toString())
|
||||||
|
|
||||||
|
function changeMusicVolume(vol: number) {
|
||||||
|
vol = Math.round(vol*100)/100
|
||||||
|
vol = Math.min(1, Math.max(0, vol))
|
||||||
|
GameMusic.setVolume(vol)
|
||||||
|
setMusicVolume(vol)
|
||||||
|
setUserSetting("MusicVolume", vol)
|
||||||
|
saveUserSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeGlobalVolume(vol: number) {
|
||||||
|
vol = Math.round(vol*100)/100
|
||||||
|
vol = Math.min(1, Math.max(0, vol))
|
||||||
|
soundManager.setGlobalVolume(vol)
|
||||||
|
setGlobalVolume(vol)
|
||||||
|
setUserSetting("GlobalVolume", vol)
|
||||||
|
saveUserSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s["settings"]}>
|
||||||
|
<div onClick={() => {
|
||||||
|
onClose?.call(null)
|
||||||
|
}} className={s["settings-close"]}>
|
||||||
|
✕
|
||||||
|
</div>
|
||||||
|
<div className={s["settings-title"]}>Settings</div>
|
||||||
|
<Setting label={"Global Volume"}>
|
||||||
|
<SettingSlider value={globalVolume} onValueChange={changeGlobalVolume} />
|
||||||
|
<div className={s["setting-value"]}>{Math.round(globalVolume * 100)}%</div>
|
||||||
|
</Setting>
|
||||||
|
<Setting label={"Music Volume"}>
|
||||||
|
<SettingSlider value={musicVolume} onValueChange={changeMusicVolume} />
|
||||||
|
<div className={s["setting-value"]}>{Math.round(musicVolume * 100)}%</div>
|
||||||
|
</Setting>
|
||||||
|
<Setting label={"Max Players"}>
|
||||||
|
<input className={s["setting-input"]} style={{
|
||||||
|
width: "min-content",
|
||||||
|
padding: ".8rem 1.8rem"
|
||||||
|
}} value={maxPlayers} onChange={(ev) => {
|
||||||
|
setMaxPlayers(ev.currentTarget.value)
|
||||||
|
}} onKeyDown={(ev) => {
|
||||||
|
if (ev.code == "Enter") {
|
||||||
|
let num = parseInt(ev.currentTarget.value)
|
||||||
|
if (isNaN(num))
|
||||||
|
num = 0
|
||||||
|
|
||||||
|
num = Math.min(8, Math.max(3, num))
|
||||||
|
|
||||||
|
ev.currentTarget.value = String(num)
|
||||||
|
setUserSetting("MaxPlayers", num)
|
||||||
|
setMaxPlayers(num.toString())
|
||||||
|
ev.currentTarget.blur()
|
||||||
|
}
|
||||||
|
}} />
|
||||||
|
</Setting>
|
||||||
|
<Setting label={"Points to Win"}>
|
||||||
|
<input className={s["setting-input"]} style={{
|
||||||
|
width: "min-content",
|
||||||
|
padding: ".8rem 1.8rem"
|
||||||
|
}} value={pointsToWin} onChange={(ev) => {
|
||||||
|
setPointsToWin(ev.currentTarget.value)
|
||||||
|
}} onKeyDown={(ev) => {
|
||||||
|
if (ev.code == "Enter") {
|
||||||
|
let num = parseInt(ev.currentTarget.value)
|
||||||
|
if (isNaN(num))
|
||||||
|
num = 0
|
||||||
|
|
||||||
|
num = Math.min(8, Math.max(3, num))
|
||||||
|
|
||||||
|
ev.currentTarget.value = String(num)
|
||||||
|
setUserSetting("PointsToWin", num)
|
||||||
|
setPointsToWin(num.toString())
|
||||||
|
ev.currentTarget.blur()
|
||||||
|
}
|
||||||
|
}} />
|
||||||
|
</Setting>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
98
src/utilities/SoundManager.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
class SoundInstance {
|
||||||
|
constructor(private readonly _soundManager: SoundManager, private readonly _audioPath: string) {}
|
||||||
|
|
||||||
|
setVolume(volume: number) {
|
||||||
|
this._volume = volume
|
||||||
|
if (this._source && this._gainControl) {
|
||||||
|
this._gainControl.gain.value = this._soundManager.adjustAudioLevels(this._volume)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVolume() {
|
||||||
|
if (this._source && this._gainControl) {
|
||||||
|
this._gainControl.gain.value = this._soundManager.adjustAudioLevels(this._volume)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
play() {
|
||||||
|
if (!this._buffer) {
|
||||||
|
console.log(`cant play audio file ${this._audioPath}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._firstTime) {
|
||||||
|
this._source!.connect(this._gainControl!).connect(this._soundManager.getContext()!.destination)
|
||||||
|
this._firstTime = false
|
||||||
|
}
|
||||||
|
|
||||||
|
this._source!.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat() {
|
||||||
|
this._source!.loop = true
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if (this._source) {
|
||||||
|
this._source.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async load() {
|
||||||
|
if (this._buffer) return;
|
||||||
|
const res = await fetch(this._audioPath)
|
||||||
|
this._source = soundManager.getContext()!.createBufferSource()
|
||||||
|
this._buffer = await this._soundManager.getContext()?.decodeAudioData(await res.arrayBuffer())
|
||||||
|
this._source.buffer = this._buffer!
|
||||||
|
|
||||||
|
this._gainControl = soundManager.getContext()!.createGain()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _source: AudioBufferSourceNode | null = null
|
||||||
|
private _buffer: AudioBuffer | undefined;
|
||||||
|
private _volume: number = 1;
|
||||||
|
private _gainControl: GainNode | null = null
|
||||||
|
private _firstTime = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class SoundManager {
|
||||||
|
init() {
|
||||||
|
this._audioContext = new AudioContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _activeSounds: SoundInstance[] = []
|
||||||
|
private _audioContext: AudioContext | null = null
|
||||||
|
private _masterVolume: number = 1
|
||||||
|
|
||||||
|
setGlobalVolume(volume: number) {
|
||||||
|
this._masterVolume = volume
|
||||||
|
this._sounds.forEach(sound => sound.updateVolume())
|
||||||
|
}
|
||||||
|
|
||||||
|
createAudio(url: string) {
|
||||||
|
const sound = new SoundInstance(this, url)
|
||||||
|
this._sounds.push(sound)
|
||||||
|
return sound
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustAudioLevels(otherVolume: number) {
|
||||||
|
return this._masterVolume * otherVolume
|
||||||
|
}
|
||||||
|
|
||||||
|
getContext() {
|
||||||
|
return this._audioContext
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAll() {
|
||||||
|
this._activeSounds.forEach((instance) => {
|
||||||
|
instance.stop()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private _sounds: SoundInstance[] = []
|
||||||
|
}
|
||||||
|
export const soundManager = new SoundManager()
|
||||||
|
await soundManager.init()
|
||||||
|
|
||||||
|
export const GameMusic = await soundManager.createAudio("/assets/sounds/game_music.mp3")
|
||||||
|
await GameMusic.load()
|
||||||
|
GameMusic.repeat()
|
||||||
1
src/vite-env.d.ts
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
||||||
25
tsconfig.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src", "../game-networking/src/types"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
||||||
10
tsconfig.node.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
25
vite.config.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
import react from "@vitejs/plugin-react";
|
||||||
|
import topLevelAwait from "vite-plugin-top-level-await";
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig(async () => ({
|
||||||
|
plugins: [react(), topLevelAwait()],
|
||||||
|
build: {
|
||||||
|
target: "esnext",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||||
|
//
|
||||||
|
// 1. prevent vite from obscuring rust errors
|
||||||
|
clearScreen: false,
|
||||||
|
// 2. tauri expects a fixed port, fail if that port is not available
|
||||||
|
server: {
|
||||||
|
port: 1420,
|
||||||
|
strictPort: true,
|
||||||
|
watch: {
|
||||||
|
// 3. tell vite to ignore watching `src-tauri`
|
||||||
|
ignored: ["**/src-tauri/**"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||