feat: Improve site user experience

- Added changes for better mobile responsive UI
- AvailabilityGrid shows players available at the selected time
master
John Montagu, the 4th Earl of Sandvich 2024-12-08 12:10:42 -08:00
parent 36bc19c96d
commit b620470739
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
9 changed files with 76 additions and 22 deletions

View File

@ -9,6 +9,8 @@ const model = defineModel();
const selectedTime = defineModel("selectedTime");
const selectedIndex = defineModel("selectedIndex");
const hoveredIndex = defineModel("hoveredIndex");
const props = defineProps({
@ -156,6 +158,7 @@ function onSlotClick(dayIndex, hour) {
}
selectedTime.value = getTimeAtCell(dayIndex, hour);
scheduleStore.selectIndex(24 * dayIndex + hour);
}
function onKeyUp($event) {

View File

@ -1,9 +1,10 @@
<script setup lang="ts">
import type { EventWithPlayerSchema } from "@/client";
import type { EventWithPlayerSchema, TeamSchema } from "@/client";
import EventCard from "./EventCard.vue";
const props = defineProps<{
events: EventWithPlayerSchema[];
teamContext: TeamSchema;
}>();
</script>
@ -12,7 +13,20 @@ const props = defineProps<{
<EventCard v-for="event in props.events" :key="event.event.id" :event="event" />
</div>
<div class="events-list" v-else>
<em class="subtext">No upcoming events.</em>
<em class="subtext">
No upcoming events. Create one in the
<router-link
:to="{
name: 'schedule',
query: {
teamId: props.teamContext.id
}
}"
>
schedule
</router-link>
page.
</em>
</div>
</template>

View File

@ -28,7 +28,7 @@ function disableIntegration() {
<template>
<h2>logs.tf Auto-Tracking</h2>
<p>Automatically fetch and track match history from logs.tf.</p>
<p>Automatically fetch and track match history from logs.tf. (CURRENTLY NOT IMPLEMENTED)</p>
<div v-if="model">
<div class="form-group margin">
<h3>logs.tf API key (optional)</h3>

View File

@ -215,7 +215,7 @@ const rightIndicator = computed(() => {
}
.player-card > td {
padding: 1em 2em;
padding: 0.5em 1em;
}
.player-card h3 {
@ -314,4 +314,10 @@ a.player-name:hover {
.edit-group > button.editing {
opacity: 1;
}
@media (max-width: 1024px) {
.player-card > td {
padding: 0.5em 0em;
}
}
</style>

View File

@ -33,10 +33,10 @@ function logout() {
</RouterLink>
</DropdownMenuItem>
<DropdownMenuItem>
<RouterLink class="button" to="/teams">
<RouterLink class="button" to="/schedule">
<button>
<i class="bi bi-people margin" />
Teams
<i class="bi bi-calendar-fill margin" />
Schedule
</button>
</RouterLink>
</DropdownMenuItem>

View File

@ -15,11 +15,20 @@ const isTeamTzLocal = computed(() => {
return selectedTimeTz.value.utcOffset() == props.selectedTime.utcOffset();
});
const props = defineProps({
selectedTime: Object
});
//const props = defineProps({
// selectedTime: Object
//});
const props = defineProps<{
selectedTime?: moment.Moment;
selectedIndex?: number;
}>();
function scheduleRoster() {
if (!props.selectedTime) {
return;
}
router.push({
name: "roster-builder",
params: {
@ -39,19 +48,20 @@ function scheduleRoster() {
:player="record"
/>
</div>
<h4>
<template v-if="selectedTime">
<h4 v-if="selectedTime">
<div>
{{ selectedTime.format("L LT z") }}
</div>
<div v-if="!isTeamTzLocal">
{{ selectedTimeTz.format("L LT z") }}
</div>
</template>
</h4>
<button @click="scheduleRoster" v-if="selectedTime">
Schedule for {{ selectedTime.format("L LT") }}
</button>
<div v-else class="subtext">
<em>Select a time to schedule</em>
</div>
</div>
</template>

View File

@ -7,10 +7,17 @@ const scheduleStore = useScheduleStore();
const hoveredIndex = computed(() => scheduleStore.hoveredIndex);
const selectedIndex = computed(() => scheduleStore.selectedIndex);
const availabilityAtHoveredIndex = computed(() => {
if (hoveredIndex.value && props.player?.availability) {
if (props.player?.availability) {
if (hoveredIndex.value) {
return props.player.availability[hoveredIndex.value] ?? 0;
}
if (scheduleStore.selectedIndexAvailability[props.player.steamId] != undefined) {
return scheduleStore.selectedIndexAvailability[props.player.steamId] ?? 0;
}
}
return undefined;
});

View File

@ -60,7 +60,16 @@ export const useScheduleStore = defineStore("schedule", () => {
const selectedMembers = reactive<{ [id: string]: boolean }>({ });
const hoveredIndex: Ref<number | undefined> = ref();
const hoveredIndex = ref<number | undefined>();
const selectedIndexAvailability = ref<{ [id: string]: number; }>({ });
function selectIndex(index: number) {
playerAvailability.value.forEach((value) => {
if (value.availability) {
selectedIndexAvailability.value[value.steamId] = value.availability[index] ?? 0;
}
});
}
const team = ref();
@ -83,10 +92,12 @@ export const useScheduleStore = defineStore("schedule", () => {
}
watch(dateStart, () => {
selectedIndexAvailability.value = { };
fetchTeamSchedule();
});
watch(team, () => {
selectedIndexAvailability.value = { };
dateStart.value = getWindowStart(team.value);
console.log(dateStart.value);
});
@ -145,6 +156,8 @@ export const useScheduleStore = defineStore("schedule", () => {
hoveredMember,
selectedMembers,
hoveredIndex,
selectedIndexAvailability,
selectIndex,
fetchSchedule,
fetchTeamSchedule,
saveSchedule,

View File

@ -27,6 +27,7 @@ const availability = schedule.availability;
const selectionMode = ref(1);
const selectedTime = ref(undefined);
const selectedIndex = ref(undefined);
const availabilityOverlay = computed(() => schedule.overlay);