Organise edit page into tabs
Use tabs for the various sections on the edit page so that the schedule timetable is more easily visible at the same time as the editable tables.
This commit is contained in:
parent
7a95d6c3c4
commit
6ef3800a53
4 changed files with 155 additions and 53 deletions
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Timetable :schedule :eventSlotFilter :shiftSlotFilter />
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -205,7 +204,6 @@ const props = defineProps<{
|
||||||
edit?: boolean,
|
edit?: boolean,
|
||||||
locationId?: number,
|
locationId?: number,
|
||||||
eventSlotFilter?: (slot: ClientScheduleEventSlot) => boolean,
|
eventSlotFilter?: (slot: ClientScheduleEventSlot) => boolean,
|
||||||
shiftSlotFilter?: (slot: ClientScheduleShiftSlot) => boolean,
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
interface EventSlot {
|
interface EventSlot {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Timetable :schedule :eventSlotFilter :shiftSlotFilter />
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -204,8 +203,6 @@ import type { Id } from '~/shared/types/common';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
edit?: boolean,
|
edit?: boolean,
|
||||||
roleId?: Id,
|
roleId?: Id,
|
||||||
eventSlotFilter?: (slot: ClientScheduleEventSlot) => boolean,
|
|
||||||
shiftSlotFilter?: (slot: ClientScheduleShiftSlot) => boolean,
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
interface ShiftSlot {
|
interface ShiftSlot {
|
||||||
|
|
86
components/Tabs.vue
Normal file
86
components/Tabs.vue
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<section class="tabs">
|
||||||
|
<nav>
|
||||||
|
<div
|
||||||
|
v-for="tab in tabs"
|
||||||
|
class="tab"
|
||||||
|
:class="{ active: tab.id === activeTab }"
|
||||||
|
>
|
||||||
|
<div class="flap">
|
||||||
|
<h2>
|
||||||
|
<NuxtLink
|
||||||
|
:to="{ ...route, query: { ...route.query, tab: tab.id }}"
|
||||||
|
>
|
||||||
|
{{ tab.title }}
|
||||||
|
</NuxtLink>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<slot :name="activeTab">No content for {{ activeTab }}</slot>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const props = defineProps<{
|
||||||
|
tabs: { id: string, title: string }[],
|
||||||
|
default: string,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const activeTab = computed({
|
||||||
|
get: () => queryToString(route.query.tab ?? props.default),
|
||||||
|
set: (value: string | undefined) => navigateTo({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
tab: value,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
nav {
|
||||||
|
margin-block: 1rem 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
row-gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.tab {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.tab.active {
|
||||||
|
padding-block-start: 1px;
|
||||||
|
}
|
||||||
|
.tab:last-child {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.tab .spacer {
|
||||||
|
flex: 1 0 0.75rem;
|
||||||
|
}
|
||||||
|
.tab .flap,
|
||||||
|
.tab .spacer {
|
||||||
|
border-block-end: 1px solid color-mix(in srgb, CanvasText, Canvas 20%);
|
||||||
|
}
|
||||||
|
.tab.active .flap {
|
||||||
|
border-block-end: none;
|
||||||
|
}
|
||||||
|
.tab:not(.active) .flap h2 {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
border: 1px solid color-mix(in srgb, CanvasText, Canvas 20%);
|
||||||
|
border-start-start-radius: 0.4rem;
|
||||||
|
border-start-end-radius: 0.4rem;
|
||||||
|
border-block-end: none;
|
||||||
|
padding-inline: 0.5rem;
|
||||||
|
margin-block: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding-block: 0.3rem 0.1rem;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -18,9 +18,18 @@
|
||||||
>{{ account.name }}</option>
|
>{{ account.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<h2>Locations</h2>
|
<Timetable :schedule :eventSlotFilter :shiftSlotFilter />
|
||||||
|
<Tabs
|
||||||
|
:tabs
|
||||||
|
default="locations"
|
||||||
|
>
|
||||||
|
<template #locations>
|
||||||
<TableScheduleLocations :edit="accountStore.canEditPublic" />
|
<TableScheduleLocations :edit="accountStore.canEditPublic" />
|
||||||
<h2>Schedule</h2>
|
</template>
|
||||||
|
<template #events>
|
||||||
|
<TableScheduleEvents :edit="true" />
|
||||||
|
</template>
|
||||||
|
<template #eventSlots>
|
||||||
<label>
|
<label>
|
||||||
Location Filter:
|
Location Filter:
|
||||||
<select
|
<select
|
||||||
|
@ -39,12 +48,15 @@
|
||||||
>{{ location.name }}</option>
|
>{{ location.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<TableScheduleEventSlots :edit="true" :locationId="locationFilter" :eventSlotFilter :shiftSlotFilter />
|
<TableScheduleEventSlots :edit="true" :locationId="locationFilter" :eventSlotFilter />
|
||||||
<h2>Events</h2>
|
</template>
|
||||||
<TableScheduleEvents :edit="true" />
|
<template #roles>
|
||||||
<h2>Roles</h2>
|
|
||||||
<TableScheduleRoles :edit="true" />
|
<TableScheduleRoles :edit="true" />
|
||||||
<h2>Shift Schedule</h2>
|
</template>
|
||||||
|
<template #shifts>
|
||||||
|
<TableScheduleShifts :edit="true" :roleId="roleFilter" />
|
||||||
|
</template>
|
||||||
|
<template #shiftSlots>
|
||||||
<label>
|
<label>
|
||||||
Role Filter:
|
Role Filter:
|
||||||
<select
|
<select
|
||||||
|
@ -63,9 +75,9 @@
|
||||||
>{{ role.name }}</option>
|
>{{ role.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<TableScheduleShiftSlots :edit="true" :roleId="roleFilter" :eventSlotFilter :shiftSlotFilter />
|
<TableScheduleShiftSlots :edit="true" :roleId="roleFilter" />
|
||||||
<h2>Shifts</h2>
|
</template>
|
||||||
<TableScheduleShifts :edit="true" :roleId="roleFilter" />
|
</Tabs>
|
||||||
<p v-if="schedule.modified">
|
<p v-if="schedule.modified">
|
||||||
Changes are not saved yet.
|
Changes are not saved yet.
|
||||||
<button
|
<button
|
||||||
|
@ -82,6 +94,15 @@ definePageMeta({
|
||||||
allowedAccountTypes: ["crew", "admin"],
|
allowedAccountTypes: ["crew", "admin"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ id: "locations", title: "Locations" },
|
||||||
|
{ id: "events", title: "Events" },
|
||||||
|
{ id: "eventSlots", title: "Event Slots" },
|
||||||
|
{ id: "roles", title: "Roles" },
|
||||||
|
{ id: "shifts", title: "Shifts" },
|
||||||
|
{ id: "shiftSlots", title: "Shifts Slots" },
|
||||||
|
];
|
||||||
|
|
||||||
const schedule = await useSchedule();
|
const schedule = await useSchedule();
|
||||||
const { data: accounts } = await useAccounts();
|
const { data: accounts } = await useAccounts();
|
||||||
const accountStore = useAccountStore();
|
const accountStore = useAccountStore();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue