Add better player card details and ringers
parent
c08f2434e6
commit
849b628130
|
@ -9,7 +9,9 @@
|
|||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"pinia": "^2.2.4",
|
||||
"v-tooltip": "^2.1.3",
|
||||
"vue": "^3.5.12",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
|
@ -68,6 +70,18 @@
|
|||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz",
|
||||
"integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.9.tgz",
|
||||
|
@ -2064,6 +2078,22 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bootstrap-icons": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz",
|
||||
"integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
|
@ -4442,7 +4472,6 @@
|
|||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
|
@ -5171,6 +5200,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
|
||||
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.47",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||
|
@ -5374,6 +5414,12 @@
|
|||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/request-progress": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
|
||||
|
@ -5676,6 +5722,16 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
|
@ -6195,6 +6251,73 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v-tooltip": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.1.3.tgz",
|
||||
"integrity": "sha512-xXngyxLQTOx/yUEy50thb8te7Qo4XU6h4LZB6cvEfVd9mnysUxLEoYwGWDdqR+l69liKsy3IPkdYff3J1gAJ5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"lodash": "^4.17.21",
|
||||
"popper.js": "^1.16.1",
|
||||
"vue-resize": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/v-tooltip/node_modules/@vue/compiler-sfc": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
|
||||
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.5",
|
||||
"postcss": "^8.4.14",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"prettier": "^1.18.2 || ^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/v-tooltip/node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/v-tooltip/node_modules/vue": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
|
||||
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
|
||||
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-sfc": "2.7.16",
|
||||
"csstype": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/v-tooltip/node_modules/vue-resize": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-1.0.1.tgz",
|
||||
"integrity": "sha512-z5M7lJs0QluJnaoMFTIeGx6dIkYxOwHThlZDeQnWZBizKblb99GSejPnK37ZbNE/rVwDcYcHY+Io+AxdpY952w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"pinia": "^2.2.4",
|
||||
"v-tooltip": "^2.1.3",
|
||||
"vue": "^3.5.12",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
@import url("tf2icons.css");
|
||||
@import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css");
|
||||
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 93 KiB |
Binary file not shown.
Binary file not shown.
|
@ -23,12 +23,26 @@ a,
|
|||
}
|
||||
|
||||
button {
|
||||
color: var(--text);
|
||||
border: none;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
background-color: var(--surface-0);
|
||||
border: none;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button.accent {
|
||||
background-color: var(--accent);
|
||||
color: var(--base);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 800;
|
||||
font-size: 300%;
|
||||
font-size: 200%;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
em.aside {
|
||||
color: var(--overlay-0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
@font-face {
|
||||
font-family: 'tf2-classicons';
|
||||
src: url('fonts/tf2-classicons.eot?bv99da');
|
||||
src: url('fonts/tf2-classicons.eot?bv99da#iefix') format('embedded-opentype'),
|
||||
url('fonts/tf2-classicons.ttf?bv99da') format('truetype'),
|
||||
url('fonts/tf2-classicons.woff?bv99da') format('woff'),
|
||||
url('fonts/tf2-classicons.svg?bv99da#tf2-classicons') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
i, .icomoon-liga {
|
||||
/* use !important to prevent issues with browser extensions that change fonts */
|
||||
font-family: 'tf2-classicons' !important;
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
|
||||
/* Enable Ligatures ================ */
|
||||
letter-spacing: 0;
|
||||
-webkit-font-feature-settings: "liga";
|
||||
-moz-font-feature-settings: "liga=1";
|
||||
-moz-font-feature-settings: "liga";
|
||||
-ms-font-feature-settings: "liga" 1;
|
||||
font-feature-settings: "liga";
|
||||
-webkit-font-variant-ligatures: discretionary-ligatures;
|
||||
font-variant-ligatures: discretionary-ligatures;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.tf2-Heavy:before {
|
||||
content: "\1f4aa";
|
||||
}
|
||||
.tf2-Medic:before {
|
||||
content: "\1f497";
|
||||
}
|
||||
.tf2-Pyro:before {
|
||||
content: "\1f525";
|
||||
}
|
||||
.tf2-Scout:before {
|
||||
content: "\1f407";
|
||||
}
|
||||
.tf2-Sniper:before {
|
||||
content: "\1f3b7";
|
||||
}
|
||||
.tf2-Soldier:before {
|
||||
content: "\1f4a5";
|
||||
}
|
||||
.tf2-Spy:before {
|
||||
content: "\1f4e6";
|
||||
}
|
||||
.tf2-Demo:before {
|
||||
content: "\1f4a3";
|
||||
}
|
||||
.tf2-Engineer:before {
|
||||
content: "\1f527";
|
||||
}
|
||||
.tf2-FlankSoldier:before {
|
||||
content: "\1f400";
|
||||
}
|
||||
.tf2-PocketSoldier:before {
|
||||
content: "\1f418";
|
||||
}
|
||||
.tf2-FlankScout:before {
|
||||
content: "\1f43f";
|
||||
}
|
||||
.tf2-PocketScout:before {
|
||||
content: "\1f416";
|
||||
}
|
|
@ -9,21 +9,47 @@ const props = defineProps({
|
|||
roleTitle: String,
|
||||
player: Object as PropType<PlayerTeamRole>,
|
||||
isRoster: Boolean,
|
||||
isRinger: Boolean,
|
||||
});
|
||||
|
||||
const isSelected = computed(() => {
|
||||
if (props.isRoster) {
|
||||
return rosterStore.selectedRole == props.roleTitle;
|
||||
}
|
||||
|
||||
if (props.isRinger) {
|
||||
return rosterStore.selectedPlayers[props.roleTitle]?.playtime == -1;
|
||||
}
|
||||
|
||||
return Object.values(rosterStore.selectedPlayers).includes(props.player);
|
||||
});
|
||||
|
||||
function onClick() {
|
||||
if (props.isRoster) {
|
||||
rosterStore.selectedRole = props.roleTitle;
|
||||
if (rosterStore.selectedRole == props.roleTitle) {
|
||||
rosterStore.selectedRole = undefined;
|
||||
} else {
|
||||
rosterStore.selectedRole = props.roleTitle;
|
||||
}
|
||||
} else {
|
||||
// we are selecting the player
|
||||
rosterStore.selectPlayerForRole(props.player, props.roleTitle);
|
||||
if (isSelected.value) {
|
||||
rosterStore.selectPlayerForRole(undefined, props.roleTitle);
|
||||
} else {
|
||||
if (props.isRinger) {
|
||||
const ringerPlayer: PlayerTeamRole = {
|
||||
steamId: -1,
|
||||
name: "Ringer",
|
||||
role: props.roleTitle,
|
||||
main: false,
|
||||
availability: 1,
|
||||
playtime: -1,
|
||||
};
|
||||
rosterStore.selectPlayerForRole(ringerPlayer, props.roleTitle);
|
||||
} else {
|
||||
rosterStore.selectPlayerForRole(props.player, props.roleTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -31,45 +57,81 @@ function onClick() {
|
|||
<template>
|
||||
<button :class="{
|
||||
'player-card': true,
|
||||
'no-player': !player,
|
||||
'no-player': !player && !isRinger,
|
||||
'selected': isSelected,
|
||||
}" @click="onClick">
|
||||
<div v-if="player">
|
||||
<h1>{{ player.name }}</h1>
|
||||
<span v-if="roleTitle != player.role">
|
||||
Subbing in as
|
||||
</span>
|
||||
{{ player.role }}
|
||||
<span v-if="!player.main">
|
||||
(alternate role)
|
||||
'can-be-available': player?.availability == 2
|
||||
}" @click="onClick">
|
||||
<div class="role-icon">
|
||||
<i :class="rosterStore.roleIcons[roleTitle]" />
|
||||
</div>
|
||||
<div v-if="player" class="role-info">
|
||||
<span>
|
||||
<h4 class="player-name">{{ player.name }}</h4>
|
||||
<span v-if="roleTitle != player.role">
|
||||
Subbing in as
|
||||
</span>
|
||||
{{ player.role }}
|
||||
<span v-if="!player.main && isRoster">
|
||||
(alternate)
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ roleTitle }}
|
||||
<div v-else-if="isRinger" class="role-info">
|
||||
<span>
|
||||
<h4 class="player-name">Ringer</h4>
|
||||
{{ roleTitle }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="role-info">
|
||||
<span>
|
||||
{{ roleTitle }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.player-card {
|
||||
background-color: var(--crust);
|
||||
background-color: white;
|
||||
padding: 1em;
|
||||
border-radius: 8px;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
align-items: center;
|
||||
border: 2px solid white;
|
||||
box-shadow: 1px 1px 8px var(--surface-0);
|
||||
}
|
||||
|
||||
.player-card.can-be-available {
|
||||
color: var(--overlay-0);
|
||||
}
|
||||
|
||||
.player-card .role-icon {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.player-card .role-info {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.player-card:hover {
|
||||
background-color: var(--surface-0);
|
||||
transition-duration: 200ms;
|
||||
border-color: var(--surface-0);
|
||||
}
|
||||
|
||||
.player-card.no-player {
|
||||
border: 2px dashed var(--overlay-0);
|
||||
border: 2px solid var(--overlay-0);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.player-card.no-player.selected {
|
||||
background-color: var(--accent-transparent);
|
||||
border: 2px dashed var(--accent);
|
||||
border: 2px solid var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
|
@ -89,8 +151,8 @@ function onClick() {
|
|||
color: var(--accent);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
.player-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,4 +9,5 @@ export interface PlayerTeamRole {
|
|||
role: string;
|
||||
main: boolean;
|
||||
availability: number;
|
||||
playtime: number;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ const router = createRouter({
|
|||
path: "/schedule/roster",
|
||||
name: "roster-builder",
|
||||
component: RosterBuilderView
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
|
||||
const selectedPlayers: Reactive<{ [key: string]: PlayerTeamRole }> = reactive({});
|
||||
|
||||
const selectedRole: Ref<String | undefined> = ref("Pocket Scout");
|
||||
const selectedRole: Ref<String | undefined> = ref(undefined);
|
||||
|
||||
const availablePlayers: Reactive<Array<PlayerTeamRole>> = reactive([
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Flank Scout",
|
||||
main: true,
|
||||
availability: 1,
|
||||
playtime: 35031,
|
||||
},
|
||||
{
|
||||
steamId: 2839,
|
||||
|
@ -30,6 +31,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Flank Scout",
|
||||
main: false,
|
||||
availability: 1,
|
||||
playtime: 28811,
|
||||
},
|
||||
{
|
||||
steamId: 2839,
|
||||
|
@ -37,6 +39,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Pocket Scout",
|
||||
main: true,
|
||||
availability: 1,
|
||||
playtime: 28811,
|
||||
},
|
||||
{
|
||||
steamId: 2841,
|
||||
|
@ -44,6 +47,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Pocket Soldier",
|
||||
main: true,
|
||||
availability: 2,
|
||||
playtime: 98372,
|
||||
},
|
||||
{
|
||||
steamId: 2841,
|
||||
|
@ -51,6 +55,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Roamer",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 98372,
|
||||
},
|
||||
{
|
||||
steamId: 2282,
|
||||
|
@ -58,6 +63,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Demoman",
|
||||
main: true,
|
||||
availability: 2,
|
||||
playtime: 47324,
|
||||
},
|
||||
{
|
||||
steamId: 2842,
|
||||
|
@ -65,6 +71,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Roamer",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 12028,
|
||||
},
|
||||
{
|
||||
steamId: 2842,
|
||||
|
@ -72,6 +79,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Demoman",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 12028,
|
||||
},
|
||||
{
|
||||
steamId: 2842,
|
||||
|
@ -79,6 +87,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Pocket Scout",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 12028,
|
||||
},
|
||||
//{
|
||||
// steamId: 2843,
|
||||
|
@ -93,6 +102,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Pocket Soldier",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 50201,
|
||||
},
|
||||
{
|
||||
steamId: 2843,
|
||||
|
@ -100,6 +110,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Roamer",
|
||||
main: false,
|
||||
availability: 2,
|
||||
playtime: 50201,
|
||||
},
|
||||
{
|
||||
steamId: 2844,
|
||||
|
@ -107,6 +118,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Roamer",
|
||||
main: true,
|
||||
availability: 1,
|
||||
playtime: 4732,
|
||||
},
|
||||
{
|
||||
steamId: 2844,
|
||||
|
@ -114,6 +126,7 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
role: "Pocket Soldier",
|
||||
main: false,
|
||||
availability: 1,
|
||||
playtime: 4732,
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -129,9 +142,27 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
return availablePlayerRoles.value.filter((player) => player.availability == 1);
|
||||
});
|
||||
|
||||
const mainRoles = computed(() => {
|
||||
return availablePlayerRoles.value.filter((player) => player.main)
|
||||
.sort((a, b) => b.playtime - a.playtime);
|
||||
});
|
||||
|
||||
const alternateRoles = computed(() => {
|
||||
return availablePlayerRoles.value.filter((player) => !player.main)
|
||||
.sort((a, b) => b.playtime - a.playtime);
|
||||
});
|
||||
|
||||
const roleIcons = reactive({
|
||||
"Pocket Scout": "tf2-PocketScout",
|
||||
"Flank Scout": "tf2-FlankScout",
|
||||
"Pocket Soldier": "tf2-PocketSoldier",
|
||||
"Roamer": "tf2-FlankSoldier",
|
||||
"Demoman": "tf2-Demo",
|
||||
"Medic": "tf2-Medic",
|
||||
});
|
||||
|
||||
function selectPlayerForRole(player: PlayerTeamRole, role: string) {
|
||||
console.log("selecting.");
|
||||
if (player) {
|
||||
if (player && player.steamId > 0) {
|
||||
const existingRole = Object.keys(selectedPlayers).find((selectedRole) => {
|
||||
return selectedPlayers[selectedRole]?.steamId == player.steamId &&
|
||||
role != selectedRole;
|
||||
|
@ -154,5 +185,8 @@ export const useRosterStore = defineStore("roster", () => {
|
|||
selectPlayerForRole,
|
||||
definitelyAvailable,
|
||||
canBeAvailable,
|
||||
roleIcons,
|
||||
mainRoles,
|
||||
alternateRoles,
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,11 +10,27 @@ const rosterStore = useRosterStore();
|
|||
const hasAvailablePlayers = computed(() => {
|
||||
return rosterStore.availablePlayerRoles.length > 0;
|
||||
});
|
||||
|
||||
const hasAlternates = computed(() => {
|
||||
return rosterStore.alternateRoles.length > 0;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<h1>Roster</h1>
|
||||
<div class="top">
|
||||
<h1 class="roster-title">
|
||||
Roster for Snus Brotherhood
|
||||
<em class="aside date">Aug. 13, 2036 @ 11:30 PM EST</em>
|
||||
</h1>
|
||||
<div class="button-group">
|
||||
<button>
|
||||
<i class="bi bi-box-arrow-left"></i>
|
||||
Back
|
||||
</button>
|
||||
<button class="accent">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<PlayerCard v-for="role in rosterStore.neededRoles"
|
||||
|
@ -23,25 +39,38 @@ const hasAvailablePlayers = computed(() => {
|
|||
is-roster />
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 v-if="hasAvailablePlayers">Available</h3>
|
||||
<PlayerCard v-for="player in rosterStore.definitelyAvailable"
|
||||
<PlayerCard v-for="player in rosterStore.mainRoles"
|
||||
:player="player"
|
||||
:role-title="player.role" />
|
||||
<span v-if="!hasAvailablePlayers">
|
||||
<span v-if="!hasAvailablePlayers && rosterStore.selectedRole">
|
||||
No players are currently available for this role.
|
||||
</span>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 v-if="hasAvailablePlayers">Available if needed</h3>
|
||||
<PlayerCard v-for="player in rosterStore.canBeAvailable"
|
||||
<h3 v-if="hasAvailablePlayers">Alternates</h3>
|
||||
<PlayerCard v-for="player in rosterStore.alternateRoles"
|
||||
:player="player"
|
||||
:role-title="player.role" />
|
||||
<PlayerCard v-if="rosterStore.selectedRole"
|
||||
is-ringer
|
||||
:role-title="rosterStore.selectedRole" />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.top {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top .button-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -57,8 +86,20 @@ const hasAvailablePlayers = computed(() => {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
h3 {
|
||||
.column h3 {
|
||||
font-weight: 700;
|
||||
color: var(--subtext-0);
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
color: var(--overlay-0);
|
||||
}
|
||||
|
||||
.roster-title {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
em.aside.date {
|
||||
font-size: 14px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<script setup lang="ts">
|
||||
import PlayerCard from "../components/PlayerCard.vue";
|
||||
import RoleSlot from "../components/RoleSlot.vue";
|
||||
import PlayerTeamRole from "../player.ts";
|
||||
import { computed, reactive } from "vue";
|
||||
import { useRosterStore } from "../stores/roster";
|
||||
|
||||
const rosterStore = useRosterStore();
|
||||
|
||||
const hasAvailablePlayers = computed(() => {
|
||||
return rosterStore.availablePlayerRoles.length > 0;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<h1 class="roster-title">
|
||||
Roster for Snus Brotherhood
|
||||
<emph class="aside date">Aug. 13, 2036 @ 11:30 PM EST</emph>
|
||||
</h1>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<PlayerCard v-for="role in rosterStore.neededRoles"
|
||||
:player="rosterStore.selectedPlayers[role]"
|
||||
:role-title="role"
|
||||
is-roster />
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 v-if="hasAvailablePlayers">Available</h3>
|
||||
<PlayerCard v-for="player in rosterStore.definitelyAvailableAll"
|
||||
:player="player"
|
||||
:role-title="player.role" />
|
||||
<span v-if="!hasAvailablePlayers">
|
||||
No players are currently available for this role.
|
||||
</span>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 v-if="hasAvailablePlayers">Available if needed</h3>
|
||||
<PlayerCard v-for="player in rosterStore.canBeAvailableAll"
|
||||
:player="player"
|
||||
:role-title="player.role" />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
margin-left: 4em;
|
||||
margin-right: 4em;
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.column h3 {
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
color: var(--overlay-0);
|
||||
}
|
||||
|
||||
.roster-title {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
emph.aside.date {
|
||||
font-size: 14px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue