Feature/draw area functionality (#4)
* fixed draw area * fixed drawarea
6
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "Cockatrice",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
|
|
@ -9,11 +9,11 @@
|
|||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/ico" href="favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="icons/cockatrice_logo-128x128.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="icons/cockatrice_logo-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/cockatrice_logo-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icons/cockatrice_logo-16x16.png">
|
||||
<link rel="icon" type="image/ico" href="cockatrice_logo.ico">
|
||||
</head>
|
||||
<body>
|
||||
<!-- quasar:entry-point -->
|
||||
|
|
|
|||
226
webclientvue/package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
|||
"dependencies": {
|
||||
"@quasar/extras": "^1.16.4",
|
||||
"quasar": "^2.16.0",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"vue": "^3.4.18",
|
||||
"vue-router": "^4.0.12"
|
||||
},
|
||||
|
|
@ -1372,6 +1373,12 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/body-parser": {
|
||||
"version": "1.19.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||
|
|
@ -3108,6 +3115,45 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
|
||||
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
|
|
@ -4791,8 +4837,7 @@
|
|||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.4.1",
|
||||
|
|
@ -6293,6 +6338,68 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
|
@ -7155,6 +7262,27 @@
|
|||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml-name-validator": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||
|
|
@ -7164,6 +7292,14 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
|
@ -8008,6 +8144,11 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"@types/body-parser": {
|
||||
"version": "1.19.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||
|
|
@ -9283,6 +9424,33 @@
|
|||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"dev": true
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
|
||||
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
|
||||
},
|
||||
"entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
|
|
@ -10493,8 +10661,7 @@
|
|||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"muggle-string": {
|
||||
"version": "0.4.1",
|
||||
|
|
@ -11472,6 +11639,46 @@
|
|||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
|
@ -12005,12 +12212,23 @@
|
|||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
|
||||
"dev": true
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
|
|
|||
|
|
@ -17,23 +17,24 @@
|
|||
"dependencies": {
|
||||
"@quasar/extras": "^1.16.4",
|
||||
"quasar": "^2.16.0",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"vue": "^3.4.18",
|
||||
"vue-router": "^4.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@quasar/app-vite": "^2.1.0",
|
||||
"@types/node": "^20.5.9",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"@vue/eslint-config-typescript": "^14.4.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"globals": "^15.12.0",
|
||||
"vue-tsc": "^2.0.29",
|
||||
"@vue/eslint-config-typescript": "^14.4.0",
|
||||
"vite-plugin-checker": "^0.9.0",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"prettier": "^3.3.3",
|
||||
"@types/node": "^20.5.9",
|
||||
"@quasar/app-vite": "^2.1.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"typescript": "~5.5.3"
|
||||
"typescript": "~5.5.3",
|
||||
"vite-plugin-checker": "^0.9.0",
|
||||
"vue-tsc": "^2.0.29"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^28 || ^26 || ^24 || ^22 || ^20 || ^18",
|
||||
|
|
|
|||
BIN
webclientvue/public/cockatrice_logo.ico
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 63 KiB |
BIN
webclientvue/public/icons/cockatrice_logo-128x128.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
webclientvue/public/icons/cockatrice_logo-16x16.png
Normal file
|
After Width: | Height: | Size: 646 B |
BIN
webclientvue/public/icons/cockatrice_logo-32x32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
webclientvue/public/icons/cockatrice_logo-96x96.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 859 B |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<q-layout view="lHh Lpr lFf">
|
||||
<q-header elevated>
|
||||
<q-toolbar>
|
||||
<q-toolbar class="toolbar">
|
||||
<CockatriceAvatar square />
|
||||
<q-toolbar-title> Webatrice </q-toolbar-title>
|
||||
<q-btn flat dense round icon="people" aria-label="Menu" @click="toggleDrawer" />
|
||||
|
|
@ -22,6 +22,13 @@
|
|||
</q-layout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.toolbar{
|
||||
min-height: 0;
|
||||
height: 5vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import Buddy, { type BuddyListProps } from 'components/BuddyList.vue';
|
||||
|
|
|
|||
|
|
@ -91,13 +91,13 @@
|
|||
<!-- relative container to make sure absolute draw area stays in bounds -->
|
||||
<div class="draw-area" ref="drawArea" style="height: 20%; width: 100%">
|
||||
<p
|
||||
class="absolute"
|
||||
style="
|
||||
font-size: 36px;
|
||||
color: white;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
font-weight: bold;
|
||||
"
|
||||
class="absolute"
|
||||
>
|
||||
DRAW AREA
|
||||
</p>
|
||||
|
|
@ -318,11 +318,10 @@ const addCard = () => {
|
|||
emitCardsToServer(); // <-- sync to server
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the board by removing all cards.
|
||||
*/
|
||||
//Clear the board by removing all cards and resetting cardId
|
||||
const clearBoard = () => {
|
||||
cards.value = [];
|
||||
cardId.value = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -346,7 +345,6 @@ const startDrag = (card: Card, e: MouseEvent) => {
|
|||
|
||||
// Get all cards at the same position (stack)
|
||||
const stack = cards.value.filter((c) => c.x === card.x && c.y === card.y);
|
||||
|
||||
// topCard is the last card in the stack (topmost visually)
|
||||
const topCard = stack[stack.length - 1];
|
||||
|
||||
|
|
@ -384,8 +382,8 @@ const dragMove = (e: MouseEvent) => {
|
|||
newY = Math.round(newY / CARD_HEIGHT) * CARD_HEIGHT;
|
||||
|
||||
// Clamp newX and newY so cards do not go out of play area
|
||||
newX = Math.max(0, Math.min(newX, rect.width - CARD_WIDTH));
|
||||
newY = Math.max(0, Math.min(newY, rect.height - CARD_HEIGHT));
|
||||
newX = Math.max(0, Math.min(newX, (Math.round(rect.width/CARD_WIDTH)*CARD_WIDTH) - CARD_WIDTH));
|
||||
newY = Math.max(0, Math.min(newY, (Math.round(rect.height/CARD_HEIGHT)*CARD_HEIGHT) - CARD_HEIGHT));
|
||||
|
||||
// Calculate how far the cards moved (delta)
|
||||
const dx = newX - dragging.value.x;
|
||||
|
|
@ -406,11 +404,19 @@ const dragMove = (e: MouseEvent) => {
|
|||
* - Removes dragged cards from the current array.
|
||||
* - Inserts dragged cards back either at the position of the stack at new location,
|
||||
* or at the end if no stack exists there.
|
||||
* - Unstacks and untaps cards cards in the draw area and auto shifts cards to fill gaps
|
||||
* - Clears dragging state and removes event listeners.
|
||||
*/
|
||||
const stopDrag = () => {
|
||||
if (!dragging.value) return;
|
||||
if (!dragging.value || !drawArea.value || !playArea.value) return;
|
||||
const draggedCards = draggedStack.value;
|
||||
const drawAreaRect = drawArea.value.getBoundingClientRect();
|
||||
const playAreaRect = playArea.value.getBoundingClientRect();
|
||||
|
||||
// Calculate drawArea's top-left relative to playArea
|
||||
const drawAreaTopRel = Math.round((drawAreaRect.top - playAreaRect.top) / CARD_HEIGHT) * CARD_HEIGHT;
|
||||
const drawAreaLeftRel = Math.round((drawAreaRect.left - playAreaRect.left) / CARD_WIDTH) * CARD_WIDTH;
|
||||
|
||||
|
||||
// Remove dragged cards from original cards array
|
||||
for (const card of draggedCards) {
|
||||
|
|
@ -433,6 +439,23 @@ const stopDrag = () => {
|
|||
cards.value.splice(insertIndex, 0, ...draggedCards);
|
||||
}
|
||||
|
||||
// Find which cards already exist horizontally in the drawArea
|
||||
const cardsInDrawArea = cards.value.filter(
|
||||
(card) =>
|
||||
card.y === drawAreaTopRel && // same y line (same row)
|
||||
card.x >= drawAreaLeftRel &&
|
||||
card.x < drawAreaLeftRel + drawAreaRect.width,
|
||||
);
|
||||
|
||||
// Sort the cards in the draw Area from left to right
|
||||
cardsInDrawArea.sort((a,b)=>a.x-b.x);
|
||||
|
||||
//Update the cards to be unstacked seperately in hand and untapped
|
||||
cardsInDrawArea.forEach((card, index)=>{
|
||||
card.x = drawAreaLeftRel + (index)*CARD_WIDTH
|
||||
card.tapped = false;
|
||||
});
|
||||
|
||||
// Reset drag state
|
||||
dragging.value = null;
|
||||
draggedStack.value = [];
|
||||
|
|
@ -447,11 +470,24 @@ const stopDrag = () => {
|
|||
|
||||
/**
|
||||
* Toggles the tapped (rotated) state for all cards in the same stack.
|
||||
* - Won't work if the card is in the draw area
|
||||
* - When a card is double-clicked, find all cards stacked with it.
|
||||
* - If the card is tapped, untap all cards in stack.
|
||||
* - Otherwise, tap all cards in stack.
|
||||
*/
|
||||
const toggleTap = (card: Card) => {
|
||||
if(drawArea.value && playArea.value){
|
||||
const drawAreaRect = drawArea.value.getBoundingClientRect();
|
||||
const playAreaRect = playArea.value.getBoundingClientRect();
|
||||
|
||||
// Calculate drawArea's top relative to playArea
|
||||
const drawAreaTopRel =
|
||||
Math.round((drawAreaRect.top - playAreaRect.top) / CARD_HEIGHT) * CARD_HEIGHT;
|
||||
|
||||
// Check if this cards exists in the drawArea and prevent toggling if so
|
||||
if(card.y >= drawAreaTopRel) return;
|
||||
}
|
||||
|
||||
// Find all cards at same position
|
||||
const sameStack = cards.value.filter((c) => c.x === card.x && c.y === card.y);
|
||||
|
||||
|
|
@ -523,7 +559,7 @@ const cardStyle = (card: Card, index: number): CSSProperties => ({
|
|||
.game {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
height: 95vh;
|
||||
background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
|
||||
}
|
||||
|
||||
|
|
@ -611,7 +647,7 @@ const cardStyle = (card: Card, index: number): CSSProperties => ({
|
|||
.draw-area {
|
||||
margin-top: auto;
|
||||
background: linear-gradient(135deg, #3498db 0%, #2980b9 50%, #1f4e79 100%);
|
||||
border-radius: 12px 12px 0 0;
|
||||
border-radius: 12px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
height: 20%;
|
||||
|
|
|
|||
|
|
@ -4,21 +4,12 @@ const routes: RouteRecordRaw[] = [
|
|||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: '', component: () => import('pages/IndexPage.vue') }],
|
||||
children: [
|
||||
{ path: '', component: () => import('pages/IndexPage.vue') },
|
||||
{ path: 'home', name: 'home', component: () => import('pages/HomePage.vue') },
|
||||
{ path: 'game', name: 'game', component: () => import('pages/GamePage.vue') },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: '',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: 'home', name: 'home', component: () => import('pages/HomePage.vue') }],
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: '',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: 'game', name: 'game', component: () => import('pages/GamePage.vue') }],
|
||||
},
|
||||
|
||||
|
||||
// Always leave this as last one,
|
||||
// but you can also remove it
|
||||
|
|
|
|||