Update roster builder

master
John Montagu, the 4th Earl of Sandvich 2024-10-24 15:13:35 -07:00
parent 684590e738
commit c08f2434e6
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
7 changed files with 246 additions and 65 deletions

View File

@ -28,6 +28,8 @@ header {
} }
nav { nav {
display: flex;
gap: 8px;
width: 100%; width: 100%;
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
@ -35,21 +37,19 @@ nav {
} }
nav a.router-link-exact-active { nav a.router-link-exact-active {
color: var(--flamingo); color: var(--crust);
} background-color: var(--accent);
nav a.router-link-exact-active:hover {
background-color: transparent;
} }
nav a { nav a {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
color: var(--subtext-0); color: var(--subtext-0);
border-radius: 8px;
} }
nav a:hover { nav a:hover {
color: var(--crust); color: var(--accent);
background-color: var(--flamingo); background-color: var(--accent-transparent);
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {

View File

@ -20,19 +20,25 @@
--vt-c-text-dark-1: var(--vt-c-white); --vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64); --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
--text: #c6d0f5; --text: #4c4f69;
--subtext-1: #b8c0e0; --subtext-1: #5c5f77;
--subtext-0: #a5adcb; --subtext-0: #6c6f85;
--overlay-2: #939ab7; --overlay-2: #7c7f93;
--overlay-1: #8087a2; --overlay-1: #8c8fa1;
--overlay-0: #6e738d; --overlay-0: #9ca0b0;
--surface-0: #ccd0da;
--base: #eff1f5;
--mantle: #e6e9ef;
--crust: #dce0e8;
--surface-0: #363a4f;
--base: #24273a;
--mantle: #1e2030;
--crust: #181926;
--flamingo: #f0c6c6; --flamingo: #f0c6c6;
--flamingo-transparent: #f0c6c655; --flamingo-transparent: #f0c6c655;
--green: #a6e3a1;
--lavender: #7287fd;
--accent: var(--lavender);
--accent-transparent: color-mix(in srgb, var(--accent), transparent 80%);
} }
/* semantic color variables for this project */ /* semantic color variables for this project */

View File

@ -11,20 +11,24 @@
a, a,
.green { .green {
text-decoration: none; text-decoration: none;
color: var(--flamingo); color: var(--accent);
transition: 0.4s; transition: 0.4s;
padding: 3px; padding: 3px;
} }
@media (hover: hover) { @media (hover: hover) {
a:hover { a:hover {
background-color: var(--flamingo-transparent); background-color: var(--accent-transparent);
} }
} }
@media (min-width: 1024px) { button {
body { color: var(--text);
display: flex; border: none;
place-items: center; }
}
h1 {
font-weight: 800;
font-size: 300%;
} }

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { PlayerTeamRole } from "../player"; import type { PlayerTeamRole } from "../player";
import type { PropType } from "vue"; import { computed, type PropType } from "vue";
import { useRosterStore } from "../stores/roster"; import { useRosterStore } from "../stores/roster";
const rosterStore = useRosterStore(); const rosterStore = useRosterStore();
@ -11,19 +11,29 @@ const props = defineProps({
isRoster: Boolean, isRoster: Boolean,
}); });
const isSelected = computed(() => {
if (props.isRoster) {
return rosterStore.selectedRole == props.roleTitle;
}
return Object.values(rosterStore.selectedPlayers).includes(props.player);
});
function onClick() { function onClick() {
if (props.isRoster) { if (props.isRoster) {
rosterStore.selectedRole = props.roleTitle; rosterStore.selectedRole = props.roleTitle;
} else {
// we are selecting the player
rosterStore.selectPlayerForRole(props.player, props.roleTitle);
} }
}; };
</script> </script>
<template> <template>
<div :class="{ <button :class="{
'player-card': true, 'player-card': true,
'no-player': !player, 'no-player': !player,
'selected': rosterStore.selectedRole == roleTitle && isRoster 'selected': isSelected,
}" @click="onClick"> }" @click="onClick">
<div v-if="player"> <div v-if="player">
<h1>{{ player.name }}</h1> <h1>{{ player.name }}</h1>
<span v-if="roleTitle != player.role"> <span v-if="roleTitle != player.role">
@ -37,7 +47,7 @@ function onClick() {
<div v-else> <div v-else>
{{ roleTitle }} {{ roleTitle }}
</div> </div>
</div> </button>
</template> </template>
<style scoped> <style scoped>
@ -49,12 +59,18 @@ function onClick() {
} }
.player-card:hover { .player-card:hover {
background-color: var(--overlay-0); background-color: var(--surface-0);
transition-duration: 200ms; transition-duration: 200ms;
} }
.player-card.no-player { .player-card.no-player {
border: 2px solid var(--overlay-0); border: 2px dashed var(--overlay-0);
}
.player-card.no-player.selected {
background-color: var(--accent-transparent);
border: 2px dashed var(--accent);
color: var(--accent);
} }
.player-card.no-player:not(.selected) { .player-card.no-player:not(.selected) {
@ -67,12 +83,14 @@ function onClick() {
} }
.player-card.selected { .player-card.selected {
background-color: var(--flamingo); border-color: var(--accent);
border-color: var(--flamingo); border: 2px solid var(--accent);
color: var(--crust); background-color: var(--accent-transparent);
color: var(--accent);
} }
h1 { h1 {
font-size: 24px; font-size: 24px;
font-weight: 700;
} }
</style> </style>

View File

@ -8,4 +8,5 @@ export interface PlayerTeamRole {
name: string; name: string;
role: string; role: string;
main: boolean; main: boolean;
availability: number;
} }

View File

@ -1,13 +1,158 @@
import { type Player } from "@/player"; import { type Player, type PlayerTeamRole } from "@/player";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { reactive, ref, type Reactive, type Ref } from "vue"; import { computed, reactive, ref, type Reactive, type Ref } from "vue";
export const useRosterStore = defineStore("roster", () => { export const useRosterStore = defineStore("roster", () => {
const neededRoles: Reactive<Array<String>> = reactive([
"Pocket Scout",
"Flank Scout",
"Pocket Soldier",
"Roamer",
"Demoman",
"Medic",
]);
const selectedPlayers: Reactive<{ [key: string]: PlayerTeamRole }> = reactive({});
const selectedRole: Ref<String | undefined> = ref("Pocket Scout"); const selectedRole: Ref<String | undefined> = ref("Pocket Scout");
const availablePlayers: Reactive<Array<Player>> = reactive([]);
const availablePlayers: Reactive<Array<PlayerTeamRole>> = reactive([
{
steamId: 2840,
name: "Wesker U",
role: "Flank Scout",
main: true,
availability: 1,
},
{
steamId: 2839,
name: "JustGetAHouse",
role: "Flank Scout",
main: false,
availability: 1,
},
{
steamId: 2839,
name: "JustGetAHouse",
role: "Pocket Scout",
main: true,
availability: 1,
},
{
steamId: 2841,
name: "VADIKUS007",
role: "Pocket Soldier",
main: true,
availability: 2,
},
{
steamId: 2841,
name: "VADIKUS007",
role: "Roamer",
main: false,
availability: 2,
},
{
steamId: 2282,
name: "Bergman777",
role: "Demoman",
main: true,
availability: 2,
},
{
steamId: 2842,
name: "BossOfThisGym",
role: "Roamer",
main: false,
availability: 2,
},
{
steamId: 2842,
name: "BossOfThisGym",
role: "Demoman",
main: false,
availability: 2,
},
{
steamId: 2842,
name: "BossOfThisGym",
role: "Pocket Scout",
main: false,
availability: 2,
},
//{
// steamId: 2843,
// name: "samme1g",
// role: "Medic",
// main: true,
// availability: 2,
//},
{
steamId: 2843,
name: "samme1g",
role: "Pocket Soldier",
main: false,
availability: 2,
},
{
steamId: 2843,
name: "samme1g",
role: "Roamer",
main: false,
availability: 2,
},
{
steamId: 2844,
name: "FarbrorBarbro",
role: "Roamer",
main: true,
availability: 1,
},
{
steamId: 2844,
name: "FarbrorBarbro",
role: "Pocket Soldier",
main: false,
availability: 1,
},
]);
const availablePlayerRoles = computed(() => {
return availablePlayers.filter((player) => player.role == selectedRole.value);
});
const definitelyAvailable = computed(() => {
return availablePlayerRoles.value.filter((player) => player.availability == 2);
});
const canBeAvailable = computed(() => {
return availablePlayerRoles.value.filter((player) => player.availability == 1);
});
function selectPlayerForRole(player: PlayerTeamRole, role: string) {
console.log("selecting.");
if (player) {
const existingRole = Object.keys(selectedPlayers).find((selectedRole) => {
return selectedPlayers[selectedRole]?.steamId == player.steamId &&
role != selectedRole;
});
if (existingRole) {
delete selectedPlayers[existingRole];
}
}
selectedPlayers[role] = player;
}
return { return {
neededRoles,
selectedPlayers,
selectedRole, selectedRole,
availablePlayers, availablePlayers,
availablePlayerRoles,
selectPlayerForRole,
definitelyAvailable,
canBeAvailable,
} }
}); });

View File

@ -2,42 +2,43 @@
import PlayerCard from "../components/PlayerCard.vue"; import PlayerCard from "../components/PlayerCard.vue";
import RoleSlot from "../components/RoleSlot.vue"; import RoleSlot from "../components/RoleSlot.vue";
import PlayerTeamRole from "../player.ts"; import PlayerTeamRole from "../player.ts";
import { reactive } from "vue"; import { computed, reactive } from "vue";
import { useRosterStore } from "../stores/roster"; import { useRosterStore } from "../stores/roster";
const rosterStore = useRosterStore(); const rosterStore = useRosterStore();
const testPlayer: PlayerTeamRole = { const hasAvailablePlayers = computed(() => {
name: "JustGetAHouse", return rosterStore.availablePlayerRoles.length > 0;
role: "Pocket Scout", });
main: false,
}
const testPlayer2: PlayerTeamRole = {
name: "Wesker U",
role: "Pocket Scout",
main: true,
}
const players = [testPlayer, testPlayer2];
const selectPlayers = reactive();
</script> </script>
<template> <template>
<div class="columns"> <main>
<div class="column"> <h1>Roster</h1>
{{ rosterStore.selectedRole }} <div class="columns">
<PlayerCard :player="testPlayer" role-title="Pocket Scout" is-roster /> <div class="column">
<PlayerCard role-title="Flank Scout" is-roster /> <PlayerCard v-for="role in rosterStore.neededRoles"
<PlayerCard role-title="Pocket Soldier" is-roster /> :player="rosterStore.selectedPlayers[role]"
<PlayerCard role-title="Roamer" is-roster /> :role-title="role"
<PlayerCard role-title="Demoman" is-roster /> is-roster />
<PlayerCard role-title="Medic" is-roster /> </div>
<div class="column">
<h3 v-if="hasAvailablePlayers">Available</h3>
<PlayerCard v-for="player in rosterStore.definitelyAvailable"
: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.canBeAvailable"
:player="player"
:role-title="player.role" />
</div>
</div> </div>
<div class="column"> </main>
</div>
</div>
</template> </template>
<style scoped> <style scoped>
@ -53,5 +54,11 @@ const selectPlayers = reactive();
margin-right: 4em; margin-right: 4em;
flex-direction: column; flex-direction: column;
row-gap: 8px; row-gap: 8px;
width: 100%;
}
h3 {
font-weight: 700;
color: var(--subtext-0);
} }
</style> </style>