Added mobile friendly display to the training reports page

This commit is contained in:
2026-03-22 10:14:53 -04:00
parent a05b48cd4c
commit b64891c2a2
2 changed files with 302 additions and 145 deletions

View File

@@ -6,8 +6,11 @@
import AlertDescription from './components/ui/alert/AlertDescription.vue';
import Navbar from './components/Navigation/Navbar.vue';
import { cancelLOA } from './api/loa';
import { onBeforeUnmount, onMounted, ref } from 'vue';
const userStore = useUserStore();
const headerRef = ref<HTMLDivElement | null>(null);
let resizeObserver: ResizeObserver | null = null;
function formatDate(dateStr) {
if (!dateStr) return "";
@@ -22,6 +25,27 @@
const environment = import.meta.env.VITE_ENVIRONMENT;
//@ts-ignore
const version = import.meta.env.VITE_APPLICATION_VERSION;
function updateHeaderHeight() {
if (!headerRef.value) return;
const height = headerRef.value.offsetHeight;
document.documentElement.style.setProperty('--app-header-height', `${height}px`);
}
onMounted(() => {
updateHeaderHeight();
// Gracefully skip observer setup for environments that do not support ResizeObserver.
if (typeof ResizeObserver === 'undefined' || !headerRef.value) return;
resizeObserver = new ResizeObserver(updateHeaderHeight);
resizeObserver.observe(headerRef.value);
});
onBeforeUnmount(() => {
resizeObserver?.disconnect();
});
</script>
<template>
@@ -29,7 +53,7 @@
background-size: contain;
background-attachment: fixed;
background-position: center;">
<div class="sticky top-0 bg-background z-50">
<div class="sticky top-0 bg-background z-50" ref="headerRef">
<Navbar class="flex"></Navbar>
<Alert v-if="environment == 'dev'" class="m-2 mx-auto max-w-5xl" variant="info">
<AlertDescription class="flex flex-row items-center text-wrap gap-5 mx-auto">

View File

@@ -205,7 +205,7 @@ const expanded = ref<number>(null);
<div class="mx-auto mt-5 flex w-full max-w-[100rem] flex-col px-3 sm:px-4 lg:flex-row lg:px-8 xl:px-20">
<!-- training report list -->
<div v-show="!isMobile || effectivePanel === sidePanelState.closed" class="my-3 px-0 lg:px-4"
:class="effectivePanel == sidePanelState.closed ? 'w-full' : 'w-full lg:w-2/5'">
:class="effectivePanel == sidePanelState.closed ? 'w-full' : 'w-full lg:flex-[0_0_26rem] xl:flex-[0_0_30rem]'">
<div class="flex justify-between mb-4">
<p class="scroll-m-20 text-2xl font-semibold tracking-tight">Training Reports</p>
<Button @click="openCreatePanel()">
@@ -323,9 +323,8 @@ const expanded = ref<number>(null);
</div>
<!-- view training report section -->
<div v-if="focusedTrainingReport != null && effectivePanel == sidePanelState.view"
:class="isMobile
? 'fixed inset-0 z-[60] overflow-y-auto bg-background px-3 py-3'
: 'my-3 mt-2 w-full lg:mt-0 lg:w-3/5 lg:border-l lg:pl-9'">
:class="isMobile ? 'fixed inset-0 z-[60] overflow-y-auto px-3 py-3' : 'my-3 mt-2 w-full min-w-0 lg:mt-0 lg:flex-1 lg:border-l lg:pl-9'"
:style="isMobile ? { top: 'var(--app-header-height, 60px)' } : {}">
<div class="flex justify-between items-center">
<p class="scroll-m-20 text-2xl font-semibold tracking-tight">Training Report Details</p>
<div class="flex items-center gap-2">
@@ -340,11 +339,11 @@ const expanded = ref<number>(null);
</Button>
</div>
</div>
<div v-if="TRLoaded" :class="isMobile ? 'my-3 pb-8' : 'max-h-[70vh] overflow-auto scrollbar-themed my-5'">
<div v-if="TRLoaded" :class="isMobile ? 'my-3 pb-8' : 'my-5 max-h-[70vh] overflow-y-auto overflow-x-hidden scrollbar-themed'">
<div class="flex flex-col mb-5 border rounded-lg bg-muted/70 p-2 py-3 px-4">
<p class="scroll-m-20 text-xl font-semibold tracking-tight">{{ focusedTrainingReport.course_name }}
</p>
<div class="flex gap-10 items-center">
<div class="mt-2 flex flex-col gap-2 text-sm sm:flex-row sm:items-center sm:gap-10">
<p class="text-muted-foreground">{{ formatDate(focusedTrainingReport.event_date) }}</p>
<div class="flex gap-2 items-center">Created by:
<MemberCard v-if="focusedTrainingReport.created_by"
@@ -357,51 +356,91 @@ const expanded = ref<number>(null);
<!-- Trainers -->
<div>
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainers</label>
<div
class="grid grid-cols-[1fr_1fr_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b">
<span>Name</span>
<span class="">Role</span>
<span class="text-right">Remarks</span>
<span></span>
</div>
<div v-for="person in focusedTrainingTrainers" class=" items-center border-b last:border-none"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<div class="grid grid-cols-[1fr_1fr_2fr_3rem] items-center py-2">
<div>
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="justify-self-start"></MemberCard>
<p v-else>{{ person.attendee_name }}</p>
</div>
<p class="">{{ person.role.name }}</p>
<p class="text-right px-2 truncate"
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
{{ person.remarks == "" ?
'--'
: person.remarks }}</p>
<div class="w-min mx-auto">
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
variant="ghost" size="icon">
<ChevronUp class="size-6" />
</Button>
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
size="icon">
<ChevronDown class="size-6" />
<div class="mt-3 space-y-2 md:hidden">
<article v-for="person in focusedTrainingTrainers" :key="person.attendee_id ?? person.attendee_name"
class="rounded-xl border bg-card p-3 shadow-sm" :class="expanded === person.attendee_id && 'ring-1 ring-primary/30'">
<div class="flex items-start justify-between gap-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="max-w-full whitespace-nowrap overflow-hidden text-ellipsis"></MemberCard>
<p v-else class="font-medium whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<Button @click.stop="expanded === person.attendee_id ? expanded = null : expanded = person.attendee_id"
variant="ghost" size="icon" class="shrink-0">
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
<ChevronUp v-else class="size-5" />
</Button>
</div>
</div>
<div class="col-span-full" v-if="expanded === person.attendee_id">
<div class="px-6 pb-5 pt-2 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<div class="mt-3 grid grid-cols-1 gap-2 text-xs">
<div class="rounded-lg bg-muted px-3 py-2">
<p class="text-muted-foreground">Role</p>
<p class="font-medium text-foreground">{{ person.role.name }}</p>
</div>
<div class="rounded-lg bg-muted px-3 py-2">
<p class="text-muted-foreground">Remarks</p>
<p class="font-medium text-foreground truncate">{{ person.remarks || '--' }}</p>
</div>
</div>
<div v-if="expanded === person.attendee_id" class="mt-3 rounded-lg border bg-background px-3 py-2">
<p class="text-sm font-medium text-foreground">Full Remarks</p>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
class="mt-1 text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="text-sm text-muted-foreground italic">
<p v-else class="mt-1 text-sm text-muted-foreground italic">
None provided
</p>
</div>
</article>
</div>
<div class="mt-2 hidden md:block">
<div
class="grid grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)_minmax(0,1.4fr)_2.5rem] py-2 text-sm font-medium text-muted-foreground border-b gap-x-2">
<span>Name</span>
<span>Role</span>
<span class="text-right">Remarks</span>
<span></span>
</div>
<div v-for="person in focusedTrainingTrainers" :key="person.attendee_id ?? person.attendee_name"
class="items-center border-b last:border-none"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<div class="grid grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)_minmax(0,1.4fr)_2.5rem] items-center py-2 gap-x-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="justify-self-start max-w-full whitespace-nowrap overflow-hidden text-ellipsis"></MemberCard>
<p v-else class="whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<p class="truncate">{{ person.role.name }}</p>
<p class="text-right px-2 truncate"
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
{{ person.remarks == "" ?
'--'
: person.remarks }}</p>
<div class="w-min mx-auto">
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
variant="ghost" size="icon">
<ChevronUp class="size-6" />
</Button>
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
size="icon">
<ChevronDown class="size-6" />
</Button>
</div>
</div>
<div class="col-span-full" v-if="expanded === person.attendee_id">
<div class="px-6 pb-5 pt-2 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="text-sm text-muted-foreground italic">
None provided
</p>
</div>
</div>
</div>
</div>
</div>
@@ -409,63 +448,110 @@ const expanded = ref<number>(null);
<div>
<div class="flex flex-col">
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainees</label>
<div
class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b px-2">
<span>Name</span>
<span class="text-center">Bookwork</span>
<span class="text-center">Qual</span>
<span class="text-right">Remarks</span>
<span class="w-15"></span>
<div class="mt-3 space-y-2 md:hidden">
<article v-for="person in focusedTrainingTrainees" :key="person.attendee_id ?? person.attendee_name"
class="rounded-xl border bg-card p-3 shadow-sm" :class="expanded === person.attendee_id && 'ring-1 ring-primary/30'">
<div class="flex items-start justify-between gap-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="max-w-full whitespace-nowrap overflow-hidden text-ellipsis"></MemberCard>
<p v-else class="font-medium whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<Button @click.stop="expanded === person.attendee_id ? expanded = null : expanded = person.attendee_id"
variant="ghost" size="icon" class="shrink-0">
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
<ChevronUp v-else class="size-5" />
</Button>
</div>
<div class="mt-3 grid grid-cols-2 gap-2 text-xs">
<div class="rounded-lg bg-muted px-3 py-2 text-center">
<p class="text-muted-foreground">Bookwork</p>
<p class="font-semibold text-foreground">{{ !focusedTrainingReport.course.hasBookwork ? 'N/A' : (person.passed_bookwork ? 'Pass' : 'Fail') }}</p>
</div>
<div class="rounded-lg bg-muted px-3 py-2 text-center">
<p class="text-muted-foreground">Qual</p>
<p class="font-semibold text-foreground">{{ !focusedTrainingReport.course.hasQual ? 'N/A' : (person.passed_qual ? 'Pass' : 'Fail') }}</p>
</div>
<div class="col-span-2 rounded-lg bg-muted px-3 py-2">
<p class="text-muted-foreground">Remarks</p>
<p class="font-medium text-foreground truncate">{{ person.remarks || '--' }}</p>
</div>
</div>
<div v-if="expanded === person.attendee_id" class="mt-3 rounded-lg border bg-background px-3 py-2">
<p class="text-sm font-medium text-foreground">Full Remarks</p>
<p v-if="person.remarks"
class="mt-1 text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="mt-1 text-sm text-muted-foreground italic">
None provided
</p>
</div>
</article>
</div>
</div>
<div v-for="person in focusedTrainingTrainees" class="border-b last:border-none"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<div class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 items-center mx-2">
<div>
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="justify-self-start"></MemberCard>
<p v-else>{{ person.attendee_name }}</p>
<div class="hidden md:block">
<div
class="grid grid-cols-[minmax(0,1.6fr)_4.25rem_4.25rem_minmax(0,1.4fr)_2.5rem] py-2 text-sm font-medium text-muted-foreground border-b px-2 gap-x-2">
<span>Name</span>
<span class="text-center">Bookwork</span>
<span class="text-center">Qual</span>
<span class="text-right">Remarks</span>
<span class="w-15"></span>
</div>
<Tooltip :open="!focusedTrainingReport.course.hasBookwork" class="mx-auto"
message="This course does not have bookwork">
<Checkbox :disabled="!focusedTrainingReport.course.hasBookwork"
:model-value="person.passed_bookwork" class="pointer-events-none">
</Checkbox>
</Tooltip>
<Tooltip :open="!focusedTrainingReport.course.hasQual" class="mx-auto"
message="This course does not have a qualification">
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
:model-value="person.passed_qual" class="pointer-events-none ml-1">
</Checkbox>
</Tooltip>
<p class="text-right truncate"
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
{{ person.remarks == "" ?
'--'
: person.remarks }}</p>
<div class="w-min mx-auto">
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
variant="ghost" size="icon">
<ChevronUp class="size-6" />
</Button>
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
size="icon">
<ChevronDown class="size-6" />
</Button>
</div>
</div>
<div class="col-span-full" v-if="expanded === person.attendee_id">
<div class="px-6 pb-5 pt-2 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="text-sm text-muted-foreground italic">
None provided
</p>
<div v-for="person in focusedTrainingTrainees" :key="person.attendee_id ?? person.attendee_name" class="border-b last:border-none"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<div class="grid grid-cols-[minmax(0,1.6fr)_4.25rem_4.25rem_minmax(0,1.4fr)_2.5rem] py-2 items-center px-2 gap-x-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="justify-self-start max-w-full whitespace-nowrap overflow-hidden text-ellipsis"></MemberCard>
<p v-else class="whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<div class="flex justify-center">
<Tooltip :open="!focusedTrainingReport.course.hasBookwork"
message="This course does not have bookwork">
<Checkbox :disabled="!focusedTrainingReport.course.hasBookwork"
:model-value="person.passed_bookwork" class="pointer-events-none">
</Checkbox>
</Tooltip>
</div>
<div class="flex justify-center">
<Tooltip :open="!focusedTrainingReport.course.hasQual"
message="This course does not have a qualification">
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
:model-value="person.passed_qual" class="pointer-events-none">
</Checkbox>
</Tooltip>
</div>
<p class="text-right truncate"
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
{{ person.remarks == "" ?
'--'
: person.remarks }}</p>
<div class="w-min mx-auto">
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
variant="ghost" size="icon">
<ChevronUp class="size-6" />
</Button>
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
size="icon">
<ChevronDown class="size-6" />
</Button>
</div>
</div>
<div class="col-span-full" v-if="expanded === person.attendee_id">
<div class="px-6 pb-5 pt-2 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="text-sm text-muted-foreground italic">
None provided
</p>
</div>
</div>
</div>
</div>
</div>
@@ -477,60 +563,108 @@ const expanded = ref<number>(null);
No Shows
</label>
<div
class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b">
<span>Name</span>
<span></span>
<span></span>
<span class="text-right">Remarks</span>
<span></span>
</div>
</div>
<div class="mt-3 space-y-2 md:hidden">
<article v-for="person in focusedNoShows" :key="person.attendee_id ?? person.attendee_name"
class="rounded-xl border bg-card p-3 shadow-sm" :class="expanded === person.attendee_id && 'ring-1 ring-primary/30'">
<div class="flex items-start justify-between gap-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="max-w-full whitespace-nowrap overflow-hidden text-ellipsis" />
<p v-else class="font-medium whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<Button variant="ghost" size="icon" class="shrink-0" @click.stop="expanded === person.attendee_id
? expanded = null
: expanded = person.attendee_id">
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
<ChevronUp v-else class="size-5" />
</Button>
</div>
<div class="mt-3 grid grid-cols-2 gap-2 text-xs">
<div class="rounded-lg bg-muted px-3 py-2 text-center">
<p class="text-muted-foreground">Bookwork</p>
<p class="font-semibold text-foreground">N/A</p>
</div>
<div class="rounded-lg bg-muted px-3 py-2 text-center">
<p class="text-muted-foreground">Qual</p>
<p class="font-semibold text-foreground">N/A</p>
</div>
<div class="col-span-2 rounded-lg bg-muted px-3 py-2">
<p class="text-muted-foreground">Remarks</p>
<p class="font-medium text-foreground truncate">{{ person.remarks || '--' }}</p>
</div>
</div>
<div v-for="person in focusedNoShows" :key="person.attendee_id ?? person.attendee_name"
class="border-b last:border-none transition-colors"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<!-- Row -->
<div class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 items-center">
<!-- Name -->
<div>
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id" />
<p v-else>{{ person.attendee_name }}</p>
<div v-if="expanded === person.attendee_id" class="mt-3 rounded-lg border bg-background px-3 py-2">
<p class="text-sm font-medium text-foreground">
Full Remarks
</p>
<p v-if="person.remarks"
class="mt-1 text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="mt-1 text-sm text-muted-foreground italic">
None provided
</p>
</div>
</article>
</div>
<div class="hidden md:block">
<div
class="grid grid-cols-[minmax(0,1.6fr)_4.25rem_4.25rem_minmax(0,1.4fr)_2.5rem] py-2 text-sm font-medium text-muted-foreground border-b gap-x-2">
<span>Name</span>
<span class="text-center">Bookwork</span>
<span class="text-center">Qual</span>
<span class="text-right">Remarks</span>
<span></span>
</div>
<div></div>
<div></div>
<div v-for="person in focusedNoShows" :key="person.attendee_id ?? person.attendee_name"
class="border-b last:border-none transition-colors"
:class="expanded === person.attendee_id && 'bg-muted/20'">
<div class="grid grid-cols-[minmax(0,1.6fr)_4.25rem_4.25rem_minmax(0,1.4fr)_2.5rem] py-2 items-center gap-x-2">
<div class="min-w-0">
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
class="max-w-full whitespace-nowrap overflow-hidden text-ellipsis" />
<p v-else class="whitespace-nowrap overflow-hidden text-ellipsis">{{ person.attendee_name }}</p>
</div>
<p class="text-right px-2 truncate" :class="!person.remarks && 'text-muted-foreground'">
{{ person.remarks || '--' }}
</p>
<p class="text-center text-muted-foreground">-</p>
<p class="text-center text-muted-foreground">-</p>
<Button variant="ghost" size="icon" @click.stop="expanded === person.attendee_id
? expanded = null
: expanded = person.attendee_id">
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
<ChevronUp v-else class="size-5" />
</Button>
</div>
<p class="text-right px-2 truncate" :class="!person.remarks && 'text-muted-foreground'">
{{ person.remarks || '--' }}
</p>
<div v-if="expanded === person.attendee_id" class="col-span-full">
<div class="px-6 py-4 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<Button variant="ghost" size="icon" @click.stop="expanded === person.attendee_id
? expanded = null
: expanded = person.attendee_id">
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
<ChevronUp v-else class="size-5" />
</Button>
</div>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<div v-if="expanded === person.attendee_id" class="col-span-full">
<div class="px-6 py-4 space-y-2">
<p class="text-sm font-medium text-foreground">
Remarks
</p>
<p v-else class="text-sm text-muted-foreground italic">
None provided
</p>
<p v-if="person.remarks"
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
{{ person.remarks }}
</p>
<p v-else class="text-sm text-muted-foreground italic">
None provided
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div>
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Remarks</label>
@@ -544,9 +678,8 @@ const expanded = ref<number>(null);
<Spinner class="size-8"></Spinner>
</div>
</div>
<div v-if="effectivePanel == sidePanelState.create" :class="isMobile
? 'fixed inset-0 z-[60] overflow-y-auto bg-background px-3 py-3'
: 'mt-2 w-full max-w-5xl lg:mt-0 lg:w-3/5 lg:border-l lg:pl-7'">
<div v-if="effectivePanel == sidePanelState.create" :class="isMobile ? 'fixed inset-0 z-[60] overflow-y-auto bg-background px-3 py-3' : 'mt-2 w-full max-w-5xl lg:mt-0 lg:w-3/5 lg:border-l lg:pl-7'"
:style="isMobile ? { top: 'var(--app-header-height, 60px)' } : {}">
<div class="flex justify-between items-center my-3">
<div class="flex gap-5 lg:pl-2">
<p class="scroll-m-20 text-2xl font-semibold tracking-tight">New Training Report</p>