adding tauri
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
src-tauri/
|
||||
node_modules/
|
69
.hmrc
@ -2,7 +2,7 @@
|
||||
"path": "G:\\Other\\Development\\Projects\\[ideas]\\domino-client",
|
||||
"name": "domino-client",
|
||||
"initialVersion": "0.1.4",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.8",
|
||||
"docker": {
|
||||
"useRegistry": true,
|
||||
"registry": "192.168.1.115:5000",
|
||||
@ -81,5 +81,72 @@
|
||||
"type": "git",
|
||||
"url": "https://gitea.xintanalabs.net/arhuako/domino-client"
|
||||
}
|
||||
},
|
||||
"_backup": {
|
||||
"name": "domino-client",
|
||||
"version": "0.1.7",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/",
|
||||
"docker-build": "docker build -t 192.168.1.115:5000/arhuako/domino-client:latest .",
|
||||
"docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-client:latest 192.168.1.115:5000/arhuako/domino-client:0.1.7",
|
||||
"docker-push": "docker push 192.168.1.115:5000/arhuako/domino-client:latest && docker push 192.168.1.115:5000/arhuako/domino-client:0.1.7",
|
||||
"publish": "npm run docker-build && npm run docker-tag && npm run docker-push",
|
||||
"serve": "npm run build-only && http-server ./dist -c-1 -s ",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pixi/sound": "^6.0.0",
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"bulma": "^1.0.1",
|
||||
"colorette": "^2.0.20",
|
||||
"dayjs": "^1.11.11",
|
||||
"pinia": "^2.1.7",
|
||||
"pino": "^9.2.0",
|
||||
"pixi-actions": "^1.1.11",
|
||||
"pixi-filters": "^6.0.4",
|
||||
"pixi.js": "^8.2.1",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"vue": "^3.4.29",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@tauri-apps/cli": "^1.6.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^20.14.5",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"http-server": "^14.1.1",
|
||||
"jsdom": "^24.1.0",
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.77.6",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
"vitest": "^1.6.0",
|
||||
"vue-tsc": "^2.0.21"
|
||||
},
|
||||
"author": "arhuako",
|
||||
"reposityory": {
|
||||
"type": "git",
|
||||
"url": "https://gitea.xintanalabs.net/arhuako/domino-client"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
CHANGELOG.md
@ -1,16 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
## 0.1.8 - 2024-07-18
|
||||
|
||||
## 0.1.7 - 2024-07-17
|
||||
|
||||
## 0.1.6 - 2024-07-17
|
||||
|
||||
## 0.1.5 - 2024-07-17
|
||||
### Added
|
||||
- Initial commit
|
||||
- Match page back button
|
||||
- Team play
|
||||
- Movement synchronized netween clients and AI players
|
||||
|
||||
### Fixed
|
||||
|
||||
- Button statuses
|
||||
|
@ -25,7 +25,9 @@ RUN npm install
|
||||
|
||||
# run webpack and the vue-loader
|
||||
RUN npm run build-only
|
||||
|
||||
RUN rm -rf .git
|
||||
RUN rm -rf .vscode
|
||||
RUN rm -rf .env
|
||||
|
||||
# copy the built app to our served directory
|
||||
RUN cp -r dist/* /var/www/html
|
||||
|
7
Dockerfile.bkp
Normal file
@ -0,0 +1,7 @@
|
||||
FROM node:22-alpine
|
||||
WORKDIR /usr/src/app
|
||||
COPY package*.json ./
|
||||
RUN npm i
|
||||
COPY . .
|
||||
EXPOSE 8080
|
||||
CMD ["npm", "run", "serve"]
|
208
package-lock.json
generated
@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "domino-client",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "domino-client",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.7",
|
||||
"dependencies": {
|
||||
"@pixi/sound": "^6.0.0",
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"bulma": "^1.0.1",
|
||||
"colorette": "^2.0.20",
|
||||
"dayjs": "^1.11.11",
|
||||
@ -25,6 +26,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@tauri-apps/cli": "^1.6.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^20.14.5",
|
||||
@ -963,6 +965,208 @@
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"node_modules/@tauri-apps/api": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz",
|
||||
"integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==",
|
||||
"engines": {
|
||||
"node": ">= 14.6.0",
|
||||
"npm": ">= 6.6.0",
|
||||
"yarn": ">= 1.19.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/tauri"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.0.tgz",
|
||||
"integrity": "sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tauri": "tauri.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/tauri"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tauri-apps/cli-darwin-arm64": "1.6.0",
|
||||
"@tauri-apps/cli-darwin-x64": "1.6.0",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "1.6.0",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "1.6.0",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "1.6.0",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "1.6.0",
|
||||
"@tauri-apps/cli-linux-x64-musl": "1.6.0",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "1.6.0",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "1.6.0",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "1.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.0.tgz",
|
||||
"integrity": "sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.0.tgz",
|
||||
"integrity": "sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.0.tgz",
|
||||
"integrity": "sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.0.tgz",
|
||||
"integrity": "sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.0.tgz",
|
||||
"integrity": "sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.0.tgz",
|
||||
"integrity": "sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.0.tgz",
|
||||
"integrity": "sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.0.tgz",
|
||||
"integrity": "sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.0.tgz",
|
||||
"integrity": "sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.0.tgz",
|
||||
"integrity": "sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node20": {
|
||||
"version": "20.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz",
|
||||
|
11
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "domino-client",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.8",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
@ -13,13 +13,15 @@
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/",
|
||||
"docker-build": "docker build -t 192.168.1.115:5000/arhuako/domino-client:latest .",
|
||||
"docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-client:latest 192.168.1.115:5000/arhuako/domino-client:0.1.4",
|
||||
"docker-push": "docker push 192.168.1.115:5000/arhuako/domino-client:latest && docker push 192.168.1.115:5000/arhuako/domino-client:0.1.4",
|
||||
"docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-client:latest 192.168.1.115:5000/arhuako/domino-client:0.1.8",
|
||||
"docker-push": "docker push 192.168.1.115:5000/arhuako/domino-client:latest && docker push 192.168.1.115:5000/arhuako/domino-client:0.1.8",
|
||||
"publish": "npm run docker-build && npm run docker-tag && npm run docker-push",
|
||||
"serve": "npm run build-only && http-server ./dist -c-1 -s "
|
||||
"serve": "npm run build-only && http-server ./dist -c-1 -s ",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pixi/sound": "^6.0.0",
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"bulma": "^1.0.1",
|
||||
"colorette": "^2.0.20",
|
||||
"dayjs": "^1.11.11",
|
||||
@ -36,6 +38,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@tauri-apps/cli": "^1.6.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^20.14.5",
|
||||
|
17
public/CHANGELOG.html
Normal file
@ -0,0 +1,17 @@
|
||||
<h1>Changelog</h1>
|
||||
<p>All notable changes to this project will be documented in this file.</p>
|
||||
<h2>0.1.8 - 2024-07-18</h2>
|
||||
<h2>0.1.7 - 2024-07-17</h2>
|
||||
<h2>0.1.6 - 2024-07-17</h2>
|
||||
<h2>0.1.5 - 2024-07-17</h2>
|
||||
<h3>Added</h3>
|
||||
<ul>
|
||||
<li>Initial commit</li>
|
||||
<li>Match page back button</li>
|
||||
<li>Team play</li>
|
||||
<li>Movement synchronized netween clients and AI players</li>
|
||||
</ul>
|
||||
<h3>Fixed</h3>
|
||||
<ul>
|
||||
<li>Button statuses</li>
|
||||
</ul>
|
3
src-tauri/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
3669
src-tauri/Cargo.lock
generated
Normal file
26
src-tauri/Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.5.3", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.7.0", features = [] }
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
||||
# 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: 11 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 49 KiB |
8
src-tauri/src/main.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
70
src-tauri/tauri.conf.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm run build-only",
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"devPath": "http://localhost:5173",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"package": {
|
||||
"productName": "domino-client",
|
||||
"version": "0.1.8"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "net.xintanalabs.domino",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"height": 720,
|
||||
"resizable": true,
|
||||
"title": "Domino",
|
||||
"width": 1280,
|
||||
"minHeight": 720,
|
||||
"minWidth": 1280,
|
||||
"center": true,
|
||||
"decorations": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -15,3 +15,9 @@
|
||||
--bulma-danger-s: 74%;
|
||||
--bulma-danger-l: 37%;
|
||||
}
|
||||
|
||||
.tabs li.is-disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
@ -1 +1,6 @@
|
||||
@import './base.css';
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export interface MatchSessionDto {
|
||||
seed: string
|
||||
waitingForPlayers: boolean
|
||||
mode: string
|
||||
pointsToWin: number
|
||||
options: MatchSessionOptions
|
||||
sessionInProgress: boolean
|
||||
status: string
|
||||
maxPlayers: number
|
||||
@ -100,15 +100,24 @@ export interface AnimationOptions {
|
||||
height?: number
|
||||
}
|
||||
|
||||
export interface GameOptions {
|
||||
boardScale?: number
|
||||
handScale?: number
|
||||
width?: number
|
||||
height?: number
|
||||
background?: string
|
||||
teamed?: boolean
|
||||
pointsToWin?: number
|
||||
export interface ScreenOptions {
|
||||
boardScale: number
|
||||
handScale: number
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
export interface MatchSessionOptions {
|
||||
screen?: ScreenOptions
|
||||
seed?: string
|
||||
background: string
|
||||
teamed: boolean
|
||||
winTarget: number
|
||||
winType: 'points' | 'rounds'
|
||||
sessionName: string
|
||||
numPlayers: 1 | 2 | 3 | 4
|
||||
}
|
||||
|
||||
export interface GameSummary {
|
||||
gameId: string
|
||||
isBlocked: boolean
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { GameDto, PlayerDto } from '@/common/interfaces'
|
||||
import type { GameDto, MatchSessionOptions, PlayerDto } from '@/common/interfaces'
|
||||
import { onMounted, onUnmounted, ref, inject } from 'vue'
|
||||
import { Game } from '@/game/Game'
|
||||
import { useGameStore } from '@/stores/game'
|
||||
@ -20,8 +20,9 @@ const { playerState, sessionState } = storeToRefs(gameStore)
|
||||
const { updateGameState } = gameStore
|
||||
const { gameOptions } = storeToRefs(gameOptionsStore)
|
||||
|
||||
const minScreenWidth = 800
|
||||
const minScreenHeight = 700
|
||||
const minScreenWidth = 1280
|
||||
const minScreenHeight = 72
|
||||
0
|
||||
|
||||
let screenWidth = window.innerWidth - 10
|
||||
let screenHeight = window.innerHeight - 10
|
||||
@ -29,48 +30,34 @@ let screenHeight = window.innerHeight - 10
|
||||
if (screenWidth < minScreenWidth) screenWidth = minScreenWidth
|
||||
if (screenHeight < minScreenHeight) screenHeight = minScreenHeight
|
||||
|
||||
const boardScale = screenWidth > 1200 ? 0.8 : screenWidth > 1200 ? 0.7 : 0.6
|
||||
const minSide = Math.min(screenWidth, screenHeight)
|
||||
|
||||
const boardScale = minSide > 1440 ? 1 : minSide > 1080 ? 0.8 : minSide > 720 ? 0.7 : 0.5
|
||||
|
||||
let appEl = ref<HTMLElement | null>(null)
|
||||
|
||||
const game = new Game(
|
||||
{
|
||||
width: screenWidth,
|
||||
height: screenHeight,
|
||||
boardScale,
|
||||
handScale: 1,
|
||||
const defaultOptions: MatchSessionOptions = {
|
||||
background: gameOptions.value?.background || 'green',
|
||||
},
|
||||
teamed: false,
|
||||
winType: 'points',
|
||||
winTarget: 100,
|
||||
seed: '',
|
||||
sessionName: `Test #${Date.now()}`,
|
||||
numPlayers: 1,
|
||||
}
|
||||
const gameOptionsValue: MatchSessionOptions = {
|
||||
...defaultOptions,
|
||||
...sessionState.value?.options,
|
||||
...{ screen: { width: screenWidth, height: screenHeight, boardScale: boardScale, handScale: 1 } },
|
||||
}
|
||||
|
||||
const game = new Game(
|
||||
gameOptionsValue,
|
||||
socketService,
|
||||
playerState.value?.id || '',
|
||||
sessionState.value?.id || '',
|
||||
)
|
||||
|
||||
// watch(
|
||||
// () => gameStore.gameState,
|
||||
// async (value: GameDto | undefined) => {
|
||||
// if (value === undefined) return
|
||||
// await game.board?.setState(value)
|
||||
// }
|
||||
// )
|
||||
|
||||
// watch(
|
||||
// () => gameStore.sessionState,
|
||||
// (value: MatchSessionDto | undefined) => {
|
||||
// if (value === undefined) return
|
||||
|
||||
// // logger.debug('gameSessionState-------------------------------------- :>> ', value)
|
||||
// }
|
||||
// )
|
||||
|
||||
// watch(
|
||||
// () => gameStore.playerState,
|
||||
// (value: PlayerDto | undefined) => {
|
||||
// if (value === undefined) return
|
||||
// game.hand.update(value as PlayerDto)
|
||||
// }
|
||||
// )
|
||||
|
||||
onMounted(async () => {
|
||||
sessionId = route.params.id as string
|
||||
if (appEl.value === null) return
|
||||
|
211
src/components/MatchConfiguration.vue
Normal file
@ -0,0 +1,211 @@
|
||||
<script setup lang="ts">
|
||||
import type { MatchSessionOptions } from '@/common/interfaces'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const emit = defineEmits(['createMatch'])
|
||||
|
||||
let options = ref<MatchSessionOptions>({
|
||||
background: 'green',
|
||||
teamed: false,
|
||||
winType: 'points',
|
||||
winTarget: 100,
|
||||
seed: '',
|
||||
sessionName: `Test #${Date.now()}`,
|
||||
numPlayers: 1,
|
||||
})
|
||||
|
||||
function createMatch() {
|
||||
emit('createMatch', options.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="grid">
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label class="label">{{ $t('mode') }}</label>
|
||||
<div class="control">
|
||||
<div class="buttons has-addons">
|
||||
<button
|
||||
class="button"
|
||||
:class="{ 'is-primary is-selected': options.numPlayers === 1 }"
|
||||
@click="
|
||||
() => {
|
||||
console.log('options :>> ', options)
|
||||
options.numPlayers = 1
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ $t('singleplayer') }}
|
||||
</button>
|
||||
<button
|
||||
class="button"
|
||||
:class="{ 'is-primary is-selected': options.numPlayers > 1 }"
|
||||
@click="
|
||||
() => {
|
||||
console.log('options :>> ', options)
|
||||
options.numPlayers = 2
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ $t('multiplayer') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="field" v-if="options.numPlayers > 1">
|
||||
<label class="label">{{ $t('players-number') }}</label>
|
||||
<div class="control">
|
||||
<div class="buttons has-addons">
|
||||
<button
|
||||
class="button is-primary"
|
||||
@click="options.numPlayers--"
|
||||
:disabled="options.numPlayers <= 2"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<button class="button is-primary" disabled>{{ options.numPlayers }}</button>
|
||||
<button
|
||||
class="button is-primary"
|
||||
@click="options.numPlayers++"
|
||||
:disabled="options.numPlayers >= 4"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="field" v-if="options.numPlayers > 1">
|
||||
<div class="control">
|
||||
<label for="teamed" class="checkbox">
|
||||
<input v-model="options.teamed" name="teamed" type="checkbox" />
|
||||
{{ $t('crossed-game-teamed') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label class="label">{{ $t('session-name') }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
v-model="options.sessionName"
|
||||
placeholder="$t('session-name-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label class="label">{{ $t('seed') }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
style="margin-bottom: 0"
|
||||
v-model="options.seed"
|
||||
:placeholder="$t('seed-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label for="background" class="label">{{ $t('background-color') }}</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select v-model="options.background" name="background">
|
||||
<option value="wood-1">{{ $t('wood-1') }}</option>
|
||||
<option value="green">{{ $t('green-fabric') }}</option>
|
||||
<option value="gray">{{ $t('gray-fabric') }}</option>
|
||||
<option value="blue">{{ $t('blue-fabric') }}</option>
|
||||
<option value="yellow">{{ $t('yellow-fabric') }}</option>
|
||||
<option value="red">{{ $t('red-fabric') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label for="winTarget" class="label">{{ $t('win-type') }}</label>
|
||||
<div class="control">
|
||||
<div class="buttons has-addons">
|
||||
<button
|
||||
class="button"
|
||||
:class="{ 'is-primary is-selected': options.winType === 'points' }"
|
||||
@click="
|
||||
() => {
|
||||
options.winType = 'points'
|
||||
options.winTarget = 100
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ $t('points') }}
|
||||
</button>
|
||||
<button
|
||||
class="button"
|
||||
:class="{ 'is-primary is-selected': options.winType === 'rounds' }"
|
||||
@click="
|
||||
() => {
|
||||
options.winType = 'rounds'
|
||||
options.winTarget = 2
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ $t('rounds') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label for="winTarget" class="label">{{ $t('points-to-win') }}</label>
|
||||
<div class="control">
|
||||
<div class="select" v-if="options.winType === 'points'">
|
||||
<select v-model="options.winTarget" name="winTarget">
|
||||
<option value="20">{{ $t('n-points', [20]) }}</option>
|
||||
<option value="50">{{ $t('n-points', [50]) }}</option>
|
||||
<option value="80">{{ $t('n-points', [80]) }}</option>
|
||||
<option value="100">{{ $t('n-points', [100]) }}</option>
|
||||
<option value="150">{{ $t('n-points', [150]) }}</option>
|
||||
<option value="200">{{ $t('n-points', [200]) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="select" v-if="options.winType === 'rounds'">
|
||||
<select v-model="options.winTarget" name="winTarget">
|
||||
<option value="1">{{ $t('n-of-m-rounds', [1, 1]) }}</option>
|
||||
<option value="2">{{ $t('n-of-m-rounds', [2, 3]) }}</option>
|
||||
<option value="3">{{ $t('n-of-m-rounds', [3, 5]) }}</option>
|
||||
<option value="4">{{ $t('n-of-m-rounds', [4, 7]) }}</option>
|
||||
<option value="5">{{ $t('n-of-m-rounds', [5, 9]) }}</option>
|
||||
<option value="6">{{ $t('n-of-m-rounds', [6, 11]) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons mt-6">
|
||||
<button class="button is-primary" @click.prevent="createMatch">
|
||||
{{ $t('create-match-session') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,9 +1,16 @@
|
||||
import { Application, Assets, Container, EventEmitter, Sprite } from 'pixi.js'
|
||||
import { Application, Assets, Container, EventEmitter, TilingSprite } from 'pixi.js'
|
||||
import { Board } from '@/game/Board'
|
||||
import { assets } from '@/game/utilities/assets'
|
||||
import { Tile } from '@/game/Tile'
|
||||
import { Hand } from '@/game/Hand'
|
||||
import type { GameDto, MatchSessionDto, Movement, PlayerDto, TileDto } from '@/common/interfaces'
|
||||
import type {
|
||||
GameDto,
|
||||
MatchSessionDto,
|
||||
MatchSessionOptions,
|
||||
Movement,
|
||||
PlayerDto,
|
||||
TileDto,
|
||||
} from '@/common/interfaces'
|
||||
import type { SocketIoClientService } from '@/services/SocketIoClientService'
|
||||
import { wait } from '@/common/helpers'
|
||||
import { Actions } from 'pixi-actions'
|
||||
@ -31,23 +38,24 @@ export class Game extends EventEmitter {
|
||||
private players: PlayerDto[] = []
|
||||
|
||||
constructor(
|
||||
private options: GameOptions = {
|
||||
boardScale: 1,
|
||||
handScale: 1,
|
||||
width: 1200,
|
||||
height: 800,
|
||||
background: 'bg-green',
|
||||
},
|
||||
private options: MatchSessionOptions,
|
||||
private socketService: SocketIoClientService,
|
||||
private playerId: string,
|
||||
private sessionId: string,
|
||||
) {
|
||||
super()
|
||||
this.options.screen = {
|
||||
width: 1280,
|
||||
height: 720,
|
||||
handScale: 1,
|
||||
boardScale: 0.7,
|
||||
...this.options.screen,
|
||||
}
|
||||
}
|
||||
|
||||
async setup(): Promise<HTMLCanvasElement> {
|
||||
const width = this.options.width || 1200
|
||||
const height = this.options.height || 800
|
||||
const width = this.options.screen?.width || 1280
|
||||
const height = this.options.screen?.height || 720
|
||||
|
||||
await this.app.init({ width, height })
|
||||
this.app.ticker.add((tick) => Actions.tick(tick.deltaTime / 60))
|
||||
@ -65,9 +73,9 @@ export class Game extends EventEmitter {
|
||||
]
|
||||
this.initPlayers(players)
|
||||
this.players = players
|
||||
this.gameSummaryView = new GameSummayView(this.app)
|
||||
this.hand.scale = this.options.handScale
|
||||
this.board.scale = this.options.boardScale
|
||||
this.gameSummaryView = new GameSummayView(this.app, this.options)
|
||||
this.hand.scale = this.options.screen?.handScale || 1
|
||||
this.board.scale = this.options.screen?.boardScale || 0.7
|
||||
this.setBoardEvents()
|
||||
this.setHandEvents()
|
||||
this.initEventBus()
|
||||
@ -80,7 +88,7 @@ export class Game extends EventEmitter {
|
||||
|
||||
iniialStuff(app: Application) {
|
||||
app.stage.addChild(this.backgroundLayer)
|
||||
const background = new Sprite(Assets.get(`bg-${this.options.background}`))
|
||||
const background = new TilingSprite(Assets.get(`bg-${this.options.background}`))
|
||||
|
||||
this.backgroundLayer.addChild(background)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createButton, createContainer } from '@/common/helpers'
|
||||
import type { GameSummary, MatchSessionDto } from '@/common/interfaces'
|
||||
import type { GameSummary, MatchSessionDto, MatchSessionOptions } from '@/common/interfaces'
|
||||
import { EventEmitter, type Application, type Container } from 'pixi.js'
|
||||
import { createText, whiteStyle, yellowStyle } from './utilities/fonts'
|
||||
|
||||
@ -12,7 +12,10 @@ export class GameSummayView extends EventEmitter {
|
||||
matchState!: MatchSessionDto
|
||||
type: 'round' | 'match' = 'round'
|
||||
|
||||
constructor(app: Application) {
|
||||
constructor(
|
||||
app: Application,
|
||||
private options: MatchSessionOptions,
|
||||
) {
|
||||
super()
|
||||
this.width = 500
|
||||
this.height = 400
|
||||
|
@ -28,10 +28,11 @@ import tile6_4 from '@/assets/images/tiles/6-4.png'
|
||||
import tile6_5 from '@/assets/images/tiles/6-5.png'
|
||||
import tile6_6 from '@/assets/images/tiles/6-6.png'
|
||||
import bgWood_1 from '@/assets/images/backgrounds/wood-1.jpg'
|
||||
import bg_1 from '@/assets/images/backgrounds/bg-1.png'
|
||||
import bg_green from '@/assets/images/backgrounds/bg-green.png'
|
||||
import bg_red from '@/assets/images/backgrounds/bg-red.png'
|
||||
import bg_yellow from '@/assets/images/backgrounds/bg-yellow.png'
|
||||
import bg_blue from '@/assets/images/backgrounds/bg-blue.png'
|
||||
import bg_gray from '@/assets/images/backgrounds/bg-1.png'
|
||||
import snd_move_1 from '@/assets/sounds/move-1.mp3'
|
||||
import snd_move_2 from '@/assets/sounds/move-2.mp3'
|
||||
import snd_move_3 from '@/assets/sounds/move-3.mp3'
|
||||
@ -69,10 +70,11 @@ export const assets = [
|
||||
{ alias: 'tile-6_5', src: tile6_5 },
|
||||
{ alias: 'tile-6_6', src: tile6_6 },
|
||||
{ alias: 'bg-wood-1', src: bgWood_1 },
|
||||
{ alias: 'bg-gray', src: bg_1 },
|
||||
{ alias: 'bg-green', src: bg_green },
|
||||
{ alias: 'bg-red', src: bg_red },
|
||||
{ alias: 'bg-yellow', src: bg_yellow },
|
||||
{ alias: 'bg-blue', src: bg_blue },
|
||||
{ alias: 'bg-gray', src: bg_gray },
|
||||
{ alias: 'snd-move-1', src: snd_move_1 },
|
||||
{ alias: 'snd-move-2', src: snd_move_2 },
|
||||
{ alias: 'snd-move-3', src: snd_move_3 },
|
||||
|
@ -8,7 +8,7 @@
|
||||
"login-button": "Login",
|
||||
"invalid-username-or-password": "Invalid username or password",
|
||||
"winner": "Winner",
|
||||
"points-to-win": "Points to win",
|
||||
"points-to-win": "Win Target",
|
||||
"final-scoreboard": "Final Scoreboard",
|
||||
"round-index-1": "Round {0}",
|
||||
"scoreboard": "Scoreboard",
|
||||
@ -26,13 +26,13 @@
|
||||
"session-name-placeholder": "Session Name",
|
||||
"seed": "Seed",
|
||||
"seed-placeholder": "Type the session seed here!",
|
||||
"background-color": "Background color",
|
||||
"background-color": "Background",
|
||||
"green-fabric": "Green Fabric",
|
||||
"gray-fabric": "Gray Fabric",
|
||||
"blue-fabric": "Blue Fabric",
|
||||
"yellow-fabric": "Yellow Fabric",
|
||||
"red-fabric": "Red Fabric",
|
||||
"crossed-game-teamed": "Crossed game ({0})",
|
||||
"crossed-game-teamed": "Crossed game",
|
||||
"create-match-session": "Create Match Session",
|
||||
"ready": "Ready",
|
||||
"unready": "Unready",
|
||||
@ -46,5 +46,18 @@
|
||||
"player-turn": "{0}'s turn!"
|
||||
},
|
||||
"back": "Back",
|
||||
"session-name": "Session Name"
|
||||
"session-name": "Session Name",
|
||||
"mode": "Mode",
|
||||
"singleplayer": "Singleplayer",
|
||||
"multiplayer": "Multiplayer",
|
||||
"players-number": "Players Number",
|
||||
"wood-1": "Wood",
|
||||
"win-type": "Win unit",
|
||||
"points": "Points",
|
||||
"rounds": "Rounds",
|
||||
"n-points": "{value} Points",
|
||||
"n-of-m-rounds": "{0} of {1} Rounds",
|
||||
"create-session": "Create Session",
|
||||
"join-a-multiplayer-session": "Join a Multiplayer Session",
|
||||
"tournaments": "Tournaments"
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
"password": "Contraseña",
|
||||
"password-placeholder": "Contraseña",
|
||||
"invalid-username-or-password": "usuario o contraseña invalido",
|
||||
"points-to-win": "Puntos para ganar",
|
||||
"points-to-win": "Objetivo para ganar",
|
||||
"round-index-1": "Ronda {0}",
|
||||
"scoreboard": "Marcador",
|
||||
"winner": "Ganador",
|
||||
@ -19,7 +19,7 @@
|
||||
"unready": "No preparado",
|
||||
"welcome-to-the-user-username-s-home-page": "Bienvenido a la página de inicio de {0}",
|
||||
"available-sessions": "Sesiones disponibles",
|
||||
"background-color": "Color de fondo",
|
||||
"background-color": "Fondo",
|
||||
"blue-fabric": "Tela azul",
|
||||
"cancel": "Cancelar",
|
||||
"copy": "Copiar",
|
||||
@ -31,7 +31,7 @@
|
||||
"your-turn": "¡Tu turno!"
|
||||
},
|
||||
"create-match-session": "Crear sesión de partido",
|
||||
"crossed-game-teamed": "Juego cruzado ({0})",
|
||||
"crossed-game-teamed": "Juego cruzado",
|
||||
"delete": "Borrar",
|
||||
"gray-fabric": "Tela gris",
|
||||
"green-fabric": "Tela verde",
|
||||
@ -46,5 +46,18 @@
|
||||
"start": "Comenzar",
|
||||
"yellow-fabric": "Tela amarilla",
|
||||
"back": "Volver",
|
||||
"session-name": "Nombre de la sesión"
|
||||
"session-name": "Nombre de la sesión",
|
||||
"mode": "Modo",
|
||||
"singleplayer": "Un jugador",
|
||||
"multiplayer": "Multijugador",
|
||||
"players-number": "Número de jugadores",
|
||||
"wood-1": "Madera",
|
||||
"win-type": "Unidad de puntaje",
|
||||
"points": "Puntos",
|
||||
"rounds": "Rondas",
|
||||
"n-points": "{0} puntos",
|
||||
"n-of-m-rounds": "{0} de {1} rondas",
|
||||
"create-session": "Crear sesión",
|
||||
"join-a-multiplayer-session": "Únete a una sesión multijugador",
|
||||
"tournaments": "Torneos"
|
||||
}
|
||||
|
@ -2,20 +2,20 @@ import { createI18n } from 'vue-i18n'
|
||||
import en from './en.json'
|
||||
import es from './es.json'
|
||||
|
||||
const browserLang = 'pt' //avigator.language.split('-')[0]
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'es',
|
||||
locale: browserLang,
|
||||
fallbackLocale: 'en',
|
||||
missingWarn: false,
|
||||
fallbackWarn: false,
|
||||
messages: {
|
||||
en,
|
||||
es,
|
||||
},
|
||||
})
|
||||
|
||||
// const translate = (key: string, context: any, plural: number = 1) => {
|
||||
// return i18n.global.t(key, plural)
|
||||
// }
|
||||
|
||||
export default i18n
|
||||
|
||||
const { t } = i18n.global
|
||||
export { t, t as $t }
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { NetworkService } from './NetworkService'
|
||||
import { ServiceBase } from './ServiceBase'
|
||||
import type { MatchSessionOptions } from '@/common/interfaces'
|
||||
|
||||
export class GameService extends ServiceBase {
|
||||
private networkService = new NetworkService()
|
||||
|
||||
async createMatchSession(sessionName: string, seed: string, options: any) {
|
||||
async createMatchSession(options: MatchSessionOptions) {
|
||||
const response = await this.networkService.post({
|
||||
uri: '/game/match',
|
||||
body: { sessionName, seed, options },
|
||||
body: { options },
|
||||
auth: true,
|
||||
})
|
||||
const { sessionId } = response
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { GameOptions } from '@/common/interfaces'
|
||||
import type { MatchSessionOptions } from '@/common/interfaces'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useGameOptionsStore = defineStore('gameOptions', () => {
|
||||
const gameOptions = ref<GameOptions>()
|
||||
const gameOptions = ref<MatchSessionOptions>()
|
||||
|
||||
return { gameOptions }
|
||||
})
|
||||
|
@ -1,23 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGameStore } from '@/stores/game'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import type { LoggingService } from '@/services/LoggingService'
|
||||
import type { GameService } from '@/services/GameService'
|
||||
import type { MatchSessionDto } from '@/common/interfaces'
|
||||
import type { MatchSessionOptions, MatchSessionDto } from '@/common/interfaces'
|
||||
import { useEventBusStore } from '@/stores/eventBus'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { copyToclipboard } from '@/common/helpers'
|
||||
import { useGameOptionsStore } from '@/stores/gameOptions'
|
||||
import MatchConfiguration from '@/components/MatchConfiguration.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
let teamedWith = ref<string | undefined>(undefined)
|
||||
|
||||
let background = ref<string>('green')
|
||||
let teamed = ref<boolean>(false)
|
||||
let pointsToWin = ref<number>(100)
|
||||
let seed = ref<string>('')
|
||||
let sessionName = ref(`Test #${Date.now()}`)
|
||||
let matchSessions = ref<MatchSessionDto[]>([])
|
||||
let dataInterval: any
|
||||
let loadingSessions = ref<boolean>(false)
|
||||
|
||||
const router = useRouter()
|
||||
const gameStore = useGameStore()
|
||||
@ -33,36 +33,18 @@ const { sessionState, isSessionStarted, playerState, amIHost, readyForStart } =
|
||||
const { user } = storeToRefs(auth)
|
||||
const { gameOptions } = storeToRefs(gameOptionsStore)
|
||||
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
|
||||
|
||||
// function setPlayerReady() {
|
||||
// logger.debug('Starting game')
|
||||
// if (!sessionState.value) {
|
||||
// logger.error('No session found')
|
||||
// return
|
||||
// }
|
||||
// if (!playerState.value) {
|
||||
// logger.error('No player found')
|
||||
// return
|
||||
// }
|
||||
// socketService.sendMessage('client:set-player-ready', {
|
||||
// userId: playerState.value.id,
|
||||
// sessionId: sessionState.value.id
|
||||
// })
|
||||
// }
|
||||
const { t } = useI18n()
|
||||
|
||||
const eventBus = useEventBusStore()
|
||||
eventBus.subscribe('window-before-unload', () => {
|
||||
logger.debug('Window before unload')
|
||||
})
|
||||
|
||||
async function createMatch() {
|
||||
async function createMatch(options: MatchSessionOptions) {
|
||||
logger.debug('Creating match')
|
||||
await socketService.connect()
|
||||
gameOptions.value = { background: background.value }
|
||||
const sessionOptions = {
|
||||
pointsToWin: pointsToWin.value,
|
||||
}
|
||||
const id = await gameService.createMatchSession(sessionName.value, seed.value, sessionOptions)
|
||||
gameOptions.value = options
|
||||
await gameService.createMatchSession(options)
|
||||
logger.debug('Match created successfully')
|
||||
// router.push({ name: 'match', params: { id } })
|
||||
}
|
||||
@ -90,6 +72,7 @@ async function startMatch() {
|
||||
await socketService.sendMessageWithAck('client:start-session', {
|
||||
sessionId: sessionId,
|
||||
playerId: playerId,
|
||||
teamedWith: teamedWith.value,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -97,13 +80,16 @@ async function startMatch() {
|
||||
async function cancelMatch() {
|
||||
logger.debug('Cancelling match')
|
||||
if (sessionState?.value?.id) {
|
||||
if (amIHost.value) {
|
||||
await gameService.cancelMatchSession(sessionState?.value?.id)
|
||||
} else {
|
||||
//TODO: await gameService.leaveMatchSession(sessionState?.value?.id)
|
||||
}
|
||||
|
||||
updateSessionState(undefined)
|
||||
updatePlayerState(undefined)
|
||||
updateGameState(undefined)
|
||||
|
||||
logger.debug('Match cancelled successfully')
|
||||
router.push({ name: 'home' })
|
||||
teamedWith.value = undefined
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,14 +113,28 @@ async function deleteMatch(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
const playersToTeamUpWith = computed(() => {
|
||||
return (
|
||||
sessionState?.value?.players.filter((player) => player.id !== sessionState?.value?.creator) ||
|
||||
[]
|
||||
)
|
||||
})
|
||||
|
||||
const canStart = computed(() => {
|
||||
const players = sessionState?.value?.players || []
|
||||
const options = gameOptions.value
|
||||
const allReady = (players.length || 0) > 0 && players.every((player) => player.ready)
|
||||
return (!options?.teamed && allReady) || (options?.teamed && !!teamedWith.value && allReady)
|
||||
})
|
||||
|
||||
async function loadData() {
|
||||
const listResponse = await gameService.listMatchSessions()
|
||||
matchSessions.value = listResponse.data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
dataInterval = setInterval(loadData, 5000)
|
||||
// loadData()
|
||||
// dataInterval = setInterval(loadData, 5000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -142,9 +142,34 @@ onUnmounted(() => {
|
||||
})
|
||||
|
||||
function copy(sessionSeed: string) {
|
||||
seed.value = sessionSeed
|
||||
copyToclipboard(sessionSeed)
|
||||
}
|
||||
|
||||
let tabs = ref<any[]>([
|
||||
{ label: t('create-session'), id: 'create-tab', active: true, disabled: false },
|
||||
{ label: t('join-a-multiplayer-session'), id: 'join-tab', active: false, disabled: false },
|
||||
{ label: t('tournaments'), id: 'torunaments-tab', active: false, disabled: true },
|
||||
])
|
||||
|
||||
const selectedTab = computed(() => tabs.value.find((t) => t.active)?.id)
|
||||
const isCreateTab = computed(() => selectedTab.value === 'create-tab')
|
||||
const isJoinTab = computed(() => selectedTab.value === 'join-tab')
|
||||
const isTournamentTab = computed(() => selectedTab.value === 'torunaments-tab')
|
||||
async function tabClick(tab: any) {
|
||||
tabs.value.forEach((t) => (t.active = t === tab))
|
||||
if (tab.id === 'join-tab') {
|
||||
loadingSessions.value = true
|
||||
await loadData()
|
||||
dataInterval = setInterval(loadData, 5000)
|
||||
} else {
|
||||
clearInterval(dataInterval)
|
||||
}
|
||||
}
|
||||
|
||||
function onCreateMatch(options: MatchSessionOptions) {
|
||||
console.log('Creating match', options)
|
||||
createMatch(options)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -153,102 +178,27 @@ function copy(sessionSeed: string) {
|
||||
<h1 class="title is-2">
|
||||
{{ $t('welcome-to-the-user-username-s-home-page', [user.username]) }}
|
||||
</h1>
|
||||
<!-- Tabs -->
|
||||
<div class="block" v-if="!isSessionStarted">
|
||||
<div class="field">
|
||||
<label class="label">{{ $t('session-name') }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
v-model="sessionName"
|
||||
placeholder="$t('session-name-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">{{ $t('seed') }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
style="margin-bottom: 0"
|
||||
v-model="seed"
|
||||
:placeholder="$t('seed-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label for="background" class="label">{{ $t('background-color') }}</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select v-model="background" name="background">
|
||||
<option value="green">{{ $t('green-fabric') }}</option>
|
||||
<option value="gray">{{ $t('gray-fabric') }}</option>
|
||||
<option value="blue">{{ $t('blue-fabric') }}</option>
|
||||
<option value="yellow">{{ $t('yellow-fabric') }}</option>
|
||||
<option value="red">{{ $t('red-fabric') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label for="teamed" class="checkbox">
|
||||
<input v-model="teamed" name="teamed" type="checkbox" />
|
||||
{{ $t('crossed-game-teamed', [teamed]) }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="field">
|
||||
<label for="pointsToWin" class="label">{{ $t('points-to-win') }}</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select v-model="pointsToWin" name="pointsToWin">
|
||||
<option value="50">50</option>
|
||||
<option value="80">80</option>
|
||||
<option value="100">100</option>
|
||||
<option value="150">150</option>
|
||||
<option value="200">200</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="button is-primary" @click.once="createMatch">
|
||||
{{ $t('create-match-session') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block" v-if="isSessionStarted">
|
||||
<h2 class="title is-4">{{ sessionState?.name }}</h2>
|
||||
<h6 class="title is-size-5">Players</h6>
|
||||
<div v-for="player in sessionState?.players" :key="player.id">
|
||||
<p>{{ player.name }}</p>
|
||||
<p>{{ player.ready ? 'Ready' : 'Not ready' }}</p>
|
||||
</div>
|
||||
<div class="buttons mt-6">
|
||||
<button class="button" @click="setPlayerReady">
|
||||
<span v-if="!readyForStart">{{ $t('ready') }}</span
|
||||
><span v-else>{{ $t('unready') }}</span>
|
||||
</button>
|
||||
<button class="button" @click="startMatch" v-if="amIHost && readyForStart">
|
||||
<span>{{ $t('start') }}</span>
|
||||
</button>
|
||||
|
||||
<button class="button" @click="cancelMatch">
|
||||
<span>{{ $t('cancel') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="tabs is-centered">
|
||||
<ul>
|
||||
<li
|
||||
v-bind:key="tab.label"
|
||||
v-for="tab in tabs"
|
||||
:class="{ 'is-active': tab.active, 'is-disabled': tab.disabled }"
|
||||
>
|
||||
<a @click="() => tabClick(tab)">{{ tab.label }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Tabs End -->
|
||||
<!-- Match Configuration -->
|
||||
<section class="section" v-if="isCreateTab">
|
||||
<MatchConfiguration @create-match="onCreateMatch" />
|
||||
</section>
|
||||
<section class="section available-sessions" v-if="!isSessionStarted">
|
||||
<h2 class="title is-4">{{ $t('available-sessions') }}</h2>
|
||||
<!-- Match Configuration End -->
|
||||
<!-- Join a Multiplayer Session -->
|
||||
<section class="section available-sessions" v-if="isJoinTab">
|
||||
<div class="block">
|
||||
<div v-if="matchSessions.length === 0">
|
||||
<p>{{ $t('no-sessions-available') }}</p>
|
||||
@ -289,6 +239,52 @@ function copy(sessionSeed: string) {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Join a Multiplayer Session End -->
|
||||
<!-- Tournaments -->
|
||||
<section class="section" v-if="isTournamentTab"></section>
|
||||
<!-- Tournaments End -->
|
||||
</div>
|
||||
|
||||
<div class="block" v-if="isSessionStarted">
|
||||
<h2 class="title is-4">{{ sessionState?.name }}</h2>
|
||||
<h6 class="title is-size-5">Players</h6>
|
||||
<div v-for="player in sessionState?.players" :key="player.id">
|
||||
<p>{{ player.name }} ({{ player.ready ? 'Ready' : 'Not ready' }})</p>
|
||||
</div>
|
||||
<div class="mt-4" v-if="amIHost && gameOptions?.teamed && playersToTeamUpWith.length > 0">
|
||||
<div class="field">
|
||||
<label for="background" class="label">Team up with</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select v-model="teamedWith" name="teamedWidth">
|
||||
<option v-for="player in playersToTeamUpWith" :key="player.id" :value="player.id">
|
||||
{{ player.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons mt-6">
|
||||
<button class="button is-dark" @click="setPlayerReady">
|
||||
<span v-if="!readyForStart">{{ $t('ready') }}</span
|
||||
><span v-else>{{ $t('unready') }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="button is-success"
|
||||
:disabled="!canStart"
|
||||
@click="startMatch"
|
||||
v-if="amIHost"
|
||||
>
|
||||
<span>{{ $t('start') }}</span>
|
||||
</button>
|
||||
|
||||
<button class="button is-danger" @click="cancelMatch">
|
||||
<span>{{ $t('cancel') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -39,9 +39,13 @@ onBeforeMount(() => {
|
||||
<span class="title is-5">{{ $t('winner') }}</span>
|
||||
<span class="is-size-5 ml-4">{{ matchSession?.matchWinner?.name }}</span>
|
||||
</p>
|
||||
<p class="mb-4">
|
||||
<span class="title is-5">{{ $t('win-type') }}</span>
|
||||
<span class="is-size-5 ml-4">{{ matchSession?.options.winType }}</span>
|
||||
</p>
|
||||
<p class="mb-4">
|
||||
<span class="title is-5">{{ $t('points-to-win') }}</span>
|
||||
<span class="is-size-5 ml-4">{{ matchSession?.pointsToWin }}</span>
|
||||
<span class="is-size-5 ml-4">{{ matchSession?.options.winTarget }}</span>
|
||||
</p>
|
||||
<h3 class="title is-5">{{ $t('final-scoreboard') }}</h3>
|
||||
<div v-bind:key="$index" v-for="(score, $index) in matchSession?.scoreboard">
|
||||
|