Improve team page usability

master
John Montagu, the 4th Earl of Sandvich 2024-11-18 11:59:13 -08:00
parent abc456b7d1
commit 9b2153266a
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
9 changed files with 129 additions and 29 deletions

View File

@ -52,6 +52,10 @@ button {
transition-duration: 200ms;
}
button.icon-end {
justify-content: space-between;
}
button.icon {
background-color: transparent;
padding: 8px;
@ -98,6 +102,10 @@ button.destructive {
color: var(--base);
}
button.destructive-on-hover:hover {
background-color: var(--flamingo);
color: var(--base);
}
button.accent:hover {
background-color: var(--text);

View File

@ -203,7 +203,7 @@ function getAvailabilityCell(day: number, hour: number) {
const currentTimezone = computed(() =>
Intl.DateTimeFormat().resolvedOptions().timeZone);
function getHour(offset, tz) {
function getHour(offset, tz?) {
let time = props.dateStart.clone()
if (tz) {
time = time.tz(tz);
@ -226,9 +226,9 @@ function getHour(offset, tz) {
</div>
<div class="height-24px hour-marker-container">
<span class="hour-marker">
{{ getHour(hour + 1).format("HH:mm z") }}
{{ getHour(lastHour + 1).format("HH:mm z") }}
<span v-if="scheduleStore.team.tzTimezone != currentTimezone">
/ {{ getHour(hour + 1, scheduleStore.team.tzTimezone).format("HH:mm z") }}
/ {{ getHour(lastHour + 1, scheduleStore.team.tzTimezone).format("HH:mm z") }}
</span>
</span>
</div>

View File

@ -33,7 +33,7 @@ function scheduleRoster() {
<template>
<div class="schedule-player-list">
<h3>{{ scheduleStore.team?.teamName }}</h3>
<div>
<div class="list">
<SchedulePlayerListItem
v-for="record in scheduleStore.playerAvailability"
:player="record"
@ -75,4 +75,9 @@ h4, h4 > div {
.player:hover {
background-color: var(--mantle);
}
.list {
display: flex;
flex-direction: column;
}
</style>

View File

@ -8,8 +8,8 @@ const scheduleStore = useScheduleStore();
const hoveredIndex = computed(() => scheduleStore.hoveredIndex);
const availabilityAtHoveredIndex = computed(() => {
if (hoveredIndex.value) {
return props.player?.availability[hoveredIndex.value] ?? 0;
if (hoveredIndex.value && props.player?.availability) {
return props.player.availability[hoveredIndex.value] ?? 0;
}
return undefined;
});
@ -19,12 +19,14 @@ const props = defineProps({
});
function onMouseOver() {
scheduleStore.overlay = props.player;
if (props.player) {
scheduleStore.hoveredMember = props.player;
}
}
function onMouseLeave() {
if (scheduleStore.overlay == props.player) {
scheduleStore.overlay = undefined;
if (scheduleStore.hoveredMember == props.player) {
scheduleStore.hoveredMember = undefined;
}
}
</script>
@ -32,28 +34,56 @@ function onMouseLeave() {
<template>
<div
class="player"
@mouseover="onMouseOver(player)"
v-if="player"
@mouseover="onMouseOver"
@mouseleave="onMouseLeave"
>
<span v-if="availabilityAtHoveredIndex > 0">
<span v-if="availabilityAtHoveredIndex == 1" class="can-be-available">
<input
class="player-checkbox"
type="checkbox"
v-model="scheduleStore.selectedMembers[player.steamId]"
:value="player"
:id="player.steamId"
/>
<label
:for="player.steamId"
>
<span v-if="availabilityAtHoveredIndex ?? 0 > 0">
<span v-if="availabilityAtHoveredIndex == 1" class="can-be-available">
{{ player.username }}
</span>
<span v-else class="available">
{{ player.username }}
</span>
</span>
<s v-else-if="availabilityAtHoveredIndex == 0">
{{ player.username }}
</s>
<span v-else>
{{ player.username }}
</span>
<span v-else class="available">
{{ player.username }}
</span>
</span>
<s v-else-if="availabilityAtHoveredIndex == 0">
{{ player.username }}
</s>
<span v-else>
{{ player.username }}
</span>
</label>
</div>
</template>
<style scoped>
.player:hover {
input {
display: inline-block;
width: unset;
}
.player {
display: flex;
gap: 4px;
padding: 6px 8px;
border-radius: 4px;
}
.player label {
flex-grow: 1;
}
.player label:hover {
background-color: var(--mantle);
}

View File

@ -19,8 +19,9 @@ export const useAuthStore = defineStore("auth", () => {
getUser.name,
() => client.default.getUser(),
(response) => {
isLoggedIn.value = true;
steamId.value = response.steamId;
username.value = username.value;
username.value = response.username;
return response;
}
);

View File

@ -29,9 +29,36 @@ export const useScheduleStore = defineStore("schedule", () => {
const playerAvailability: Ref<AvailabilitySchema[]> = ref([ ]);
const overlay: Ref<AvailabilitySchema[] | undefined> = ref();
const overlay = computed<number[] | undefined>(() => {
let members = Object.keys(selectedMembers)
.filter((x) => selectedMembers[x]);
if (members.length > 0) {
const min = Array(168).fill(0);
const selectedMembers = ref<AvailabilitySchema[]>();
const candidates = playerAvailability.value
.filter((x) => members.includes(x.steamId));
for (let i = 0; i < 168; i++) {
min[i] = Math.min(
...candidates.map((c) => c.availability ? c.availability[i] : 0));
}
//for (const availability of candidates) {
//}
return min;
}
if (hoveredMember.value) {
return playerAvailability.value
.find((x) => x.steamId == hoveredMember.value?.steamId)
?.availability;
}
return undefined;
});
const hoveredMember = ref<AvailabilitySchema>();
const selectedMembers = reactive<{ [id: string]: boolean }>({ });
const hoveredIndex: Ref<number | undefined> = ref();
@ -115,6 +142,7 @@ export const useScheduleStore = defineStore("schedule", () => {
availability,
playerAvailability,
overlay,
hoveredMember,
selectedMembers,
hoveredIndex,
fetchSchedule,

View File

@ -28,7 +28,7 @@ const selectionMode = ref(1);
const selectedTime = ref(undefined);
const availabilityOverlay = computed(() => schedule.overlay?.availability);
const availabilityOverlay = computed(() => schedule.overlay);
const isEditing = ref(false);
@ -132,7 +132,8 @@ onMounted(() => {
Copy previous week
</button>
<button class="accent" @click="isEditing = true">
<i class="bi bi-pencil-fill"></i>
<i class="bi bi-pencil-fill margin"></i>
Edit
</button>
</template>
</div>

View File

@ -7,6 +7,10 @@ const {
timezone,
minuteOffset,
} = useTeamSettings();
function updateTeamSettings() {
}
</script>
<template>

View File

@ -2,15 +2,21 @@
import { useTeamsStore } from "@/stores/teams";
import { useTeamDetails } from "@/composables/team-details";
import { onMounted } from "vue";
import { RouterLink, RouterView } from "vue-router";
import { RouterLink, RouterView, useRouter } from "vue-router";
const teamsStore = useTeamsStore();
const router = useRouter();
const {
team,
teamId,
} = useTeamDetails();
function leaveTeam() {
teamsStore.leaveTeam(teamId.value)
.then(() => router.push("/"));
}
onMounted(() => {
teamsStore.fetchTeam(teamId.value);
});
@ -37,6 +43,10 @@ onMounted(() => {
Invites
</RouterLink>
<hr>
<button class="destructive-on-hover icon-end" @click="leaveTeam">
Leave team
<i class="bi bi-box-arrow-left" />
</button>
</div>
</nav>
<div class="view">
@ -96,4 +106,17 @@ nav.sidebar a.tab.router-link-exact-active {
background-color: var(--crust);
color: var(--text);
}
nav.sidebar button {
font-size: 11pt;
font-weight: 500;
padding: 6px 10px;
background-color: transparent;
color: var(--overlay-0);
}
nav.sidebar button:hover {
background-color: var(--crust);
color: var(--text);
}
</style>