Reorganizace skeletonu, aktualizace app-vite a quasaru

This commit is contained in:
Michal Kváček
2023-12-10 10:19:03 +01:00
parent 68659ca924
commit 71389caecc
87 changed files with 1666 additions and 1368 deletions
+5
View File
@@ -3,6 +3,11 @@ import {computed} from "vue";
import {useQuasar} from "quasar";
const props = defineProps({
isRequestPending: {
type: Boolean,
required: false,
default: false,
},
saveButton: {
type: [Object, Boolean],
required: false,
+6 -5
View File
@@ -1,14 +1,15 @@
<script setup>
import {isRequestPending} from "src/composables/form/props";
import {computed, useSlots} from "vue";
import {useQuasar} from "quasar";
import FormSubmitButton from "components/FormSubmitButton.vue";
const props = defineProps({
modelValue: {
type: Object,
},
isRequestPending,
isRequestPending: {
type: Boolean,
required: false,
default: false,
},
saveButton: {
type: [Object, Boolean],
required: false,
@@ -29,6 +30,6 @@ const saveForm = () => {
<template>
<q-form @submit.prevent="saveForm" ref="form">
<slot name="default"/>
<FormSubmitButton v-if="saveButton" :save-button="saveButton" />
<FormSubmitButton v-if="saveButton" :save-button="saveButton"/>
</q-form>
</template>
+39 -32
View File
@@ -2,7 +2,6 @@
import {onMounted, reactive} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import {defaultValues, isRequestPending} from "src/composables/form/props";
import {isNumber, isRequired, maxLength, minLength} from "src/composables/form/rules";
import {commonProps} from "src/composables/inputs";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
@@ -19,8 +18,16 @@ const formData = reactive({
});
const props = defineProps({
defaultValues,
isRequestPending,
defaultValues: {
type: Object,
required: false,
default: () => ({})
},
isRequestPending: {
type: Boolean,
required: false,
default: false,
},
organizations: {
type: Array,
required: true,
@@ -47,48 +54,48 @@ onMounted(() => {
<q-img :src="props.defaultValues.photoUrl" v-if="props.defaultValues.photoUrl"/>
<q-input
type="text"
:rules="rules.callSign"
v-model="formData.callSign"
label="Volací značka"
v-bind="commonProps"
type="text"
:rules="rules.callSign"
v-model="formData.callSign"
label="Volací značka"
v-bind="commonProps"
/>
<q-input
type="number"
v-model.number="formData.seats"
label="Počet míst (včetně pilota)"
min="1"
:rules="rules.seats"
v-bind="commonProps"
<q-input
type="number"
v-model.number="formData.seats"
label="Počet míst (včetně pilota)"
min="1"
:rules="rules.seats"
v-bind="commonProps"
/>
<ComboboxInput
:options="organizations"
label="Organizace"
v-model="formData.organization"
v-bind="commonProps"
hint="Vyber provozovatele letadla. Tím se stane dostupné i pro ostatní členy vybrané organizace."
:options="organizations"
label="Organizace"
v-model="formData.organization"
v-bind="commonProps"
hint="Vyber provozovatele letadla. Tím se stane dostupné i pro ostatní členy vybrané organizace."
/>
<q-input
type="text"
v-model="formData.manufacturer"
label="Výrobce"
v-bind="commonProps"
type="text"
v-model="formData.manufacturer"
label="Výrobce"
v-bind="commonProps"
/>
<q-input
type="text"
v-model="formData.model"
label="Model"
v-bind="commonProps"
type="text"
v-model="formData.model"
label="Model"
v-bind="commonProps"
/>
<q-input
type="textarea"
v-model="formData.description"
label="Popis"
v-bind="commonProps"
type="textarea"
v-model="formData.description"
label="Popis"
v-bind="commonProps"
/>
<q-checkbox v-model="formData.isPublic" label="Veřejné?" v-bind="commonProps"/>
@@ -14,7 +14,8 @@ const props = defineProps({
default: 5
},
items: {
type: Number, required: false,
type: Number,
required: false,
}
});
+5 -2
View File
@@ -4,14 +4,17 @@ import {onMounted, reactive} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import FormWrapper from "components/FormWrapper.vue";
import {commonProps} from "src/composables/inputs";
import {isRequestPending} from "src/composables/form/props";
import {isRequired} from "src/composables/form/rules";
const props = defineProps({
copilot: {
type: Object
},
isRequestPending
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
})
const formData = reactive({
+4 -1
View File
@@ -17,7 +17,10 @@ const props = defineProps({
v-ripple
v-for="pilot of items" :key="pilot">
<q-item-section avatar>
<q-avatar icon="person" color="primary" text-color="white"/>
<q-avatar v-if="pilot.titlePhoto">
<img :src="pilot.titlePhoto.thumbnailUrl" alt=""/>
</q-avatar>
<q-avatar v-else icon="person" color="primary" text-color="white"/>
</q-item-section>
<q-item-section>
{{ pilot.name }}
+5 -2
View File
@@ -4,7 +4,6 @@ import {onMounted, reactive} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import FormWrapper from "components/FormWrapper.vue";
import {commonProps} from "src/composables/inputs";
import {isRequestPending} from "src/composables/form/props";
import {isRequired} from "src/composables/form/rules";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import DatetimePicker from "components/inputs/DatetimePicker.vue";
@@ -14,7 +13,11 @@ const props = defineProps({
event: {
type: Object
},
isRequestPending
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
})
const formData = reactive({
+1 -1
View File
@@ -13,7 +13,7 @@ const props = defineProps({
},
});
const getCoverPhotos = (item) => item.flights.filter(f => !!f.coverPhoto).map(f => f.coverPhoto.thumbnailUrl);
const getCoverPhotos = (item) => item.flights.filter(f => !!f.titlePhoto).map(f => f.titlePhoto.thumbnailUrl);
</script>
<template>
@@ -13,5 +13,5 @@ import ListItemSkeleton from "components/basicSkeletons/ListItemSkeleton.vue";
<BasicTextSkeleton :lines="3" :paragraphs="2"/>
<BasicListSkeleton :items-count-min="1" :items-count-max="5"/>
<BasicListSkeleton :items="4"/>
</template>
@@ -6,7 +6,6 @@ import DatetimePicker from "components/inputs/DatetimePicker.vue";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {commonProps} from "src/composables/inputs";
import {isRequired} from "src/composables/form/rules";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
aircrafts: {
@@ -21,7 +20,11 @@ const props = defineProps({
type: Object,
required: false
},
isRequestPending,
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
});
const airportName = (airport) => `${airport.icaoCode} (${airport.name})`;
@@ -5,7 +5,6 @@ import {setDefaultData} from "src/composables/form/formHandling";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import {commonProps} from "src/composables/inputs";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
flight: {
@@ -16,7 +15,11 @@ const props = defineProps({
type: Array,
required: false,
},
isRequestPending
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
});
const formData = reactive({
@@ -0,0 +1,7 @@
<script setup>
</script>
<template>
edit copilot skeleton
</template>
@@ -3,7 +3,7 @@ import {randomInt} from "src/composables/random";
</script>
<template>
<q-list bordered separator class="q-mx-md q-my-md">
<q-list bordered separator>
<q-item v-for="i in 10" :key="i" ripple>
<q-item-section avatar>
<q-avatar size="100px">
@@ -8,7 +8,7 @@ const props = defineProps({
</script>
<template>
<q-breadcrumbs>
<q-breadcrumbs class="q-mx-md q-my-md">
<q-breadcrumbs-el v-for="item in items" :key="item.label" :to="item.to"> {{ item.label }} </q-breadcrumbs-el>
</q-breadcrumbs>
</template>
@@ -0,0 +1,14 @@
<script setup>
import {randomInt} from "src/composables/random";
</script>
<template>
<q-breadcrumbs class="q-mx-md q-my-md">
<q-breadcrumbs-el> <q-skeleton :width="`${randomInt(30, 60)}px`" type="rect" /> </q-breadcrumbs-el>
<q-breadcrumbs-el> <q-skeleton :width="`${randomInt(40, 80)}px`" type="rect" /> </q-breadcrumbs-el>
</q-breadcrumbs>
</template>
@@ -0,0 +1,27 @@
<script setup>
const props = defineProps({
route: {
type: Object,
required: true
}
});
</script>
<template>
<q-tabs active-color="primary" class="q-mb-lg">
<q-route-tab
icon="edit"
label="Informace"
replace
:to="{name: route.name, params: {...route.params, step: 'info'}}"
exact
/>
<q-route-tab
icon="add_a_photo"
label="Fotky"
replace
:to="{name: route.name, params: {...route.params, step: 'photo'}}"
exact100
/>
</q-tabs>
</template>
@@ -4,15 +4,17 @@ import {onMounted, reactive} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import FormWrapper from "components/FormWrapper.vue";
import {commonProps} from "src/composables/inputs";
import {isRequestPending} from "src/composables/form/props";
import {isRequired} from "src/composables/form/rules";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
const props = defineProps({
organization: {
type: Object
},
isRequestPending
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
})
const formData = reactive({
+23 -15
View File
@@ -13,8 +13,8 @@ const props = defineProps({
locations: {
type: Array
},
aircraft: {
type: Object
aircrafts: {
type: Array
},
copilots: {
type: Array
@@ -26,7 +26,7 @@ const formData = ref({
description: "",
pointOfInterest: null,
copilots: [],
isAircraft: false,
aircraftId: null,
photoIds: []
});
@@ -42,7 +42,7 @@ const setup = () => {
<template>
<DialogWrapper :formData="formData" @show="setup()">
<q-card-section class="text-center">
<q-img :src="photo.thumbnailUrl" width="80px" class="q-ma-sm" v-for="photo in photos" :key="photo.thumbnailUrl"/>
<q-img :src="photo.thumbnailUrl" width="80px" class="q-ma-sm" v-for="photo in photos" :key="photo.thumbnailUrl"/>
</q-card-section>
<q-card-section>
<FormWrapper :save-button="false">
@@ -54,19 +54,27 @@ const setup = () => {
label="Místo"
/>
<q-select
v-if="copilots.length > 0"
:options="copilots"
v-model="formData.copilots"
v-bind="commonProps"
label="Kopiloti"
option-label="name"
option-value="id"
multiple
<q-select
v-if="copilots.length > 0"
:options="copilots"
v-model="formData.copilots"
v-bind="commonProps"
label="Kopiloti"
option-label="name"
option-value="id"
multiple
/>
<q-checkbox v-model="formData.isAircraft" :label="`Letadlo (${aircraft.callSign})`"/>
<q-select
:options="aircrafts"
v-model="formData.aircraftId"
v-bind="commonProps"
label="Letadlo"
option-label="callSign"
option-value="id"
emit-value
map-options
/>
<q-input v-model="formData.name" label="Název" v-bind="commonProps"/>
<q-input type="textarea" v-model="formData.description" label="Popis" v-bind="commonProps"/>
</FormWrapper>
+14 -4
View File
@@ -13,8 +13,8 @@ const props = defineProps({
locations: {
type: Array
},
aircraft: {
type: Object
aircrafts: {
type: Array
},
copilots: {
type: Array
@@ -27,7 +27,7 @@ const formData = ref({
description: "",
pointOfInterest: null,
copilots: [],
isAircraft: false,
aircraftId: null,
});
const setup = (() => {
@@ -58,7 +58,17 @@ const setup = (() => {
multiple
/>
<q-checkbox v-model="formData.isAircraft" :label="`Letadlo (${aircraft.callSign})`"/>
<q-select
:options="aircrafts"
v-model="formData.aircraftId"
v-bind="commonProps"
label="Letadlo"
option-label="callSign"
option-value="id"
emit-value
map-options
/>
<q-input v-model="formData.name" label="Název" v-bind="commonProps"/>
<q-input type="textarea" v-model="formData.description" label="Popis" v-bind="commonProps"/>
</FormWrapper>
+36 -18
View File
@@ -34,20 +34,20 @@ const openEdit = (photo) => {
const confirmPhotoDelete = (id) => {
$q.dialog(confirmObject("Opravdu chces smazat tuto fotku?"))
.onOk(() => {
emits("delete", id);
});
.onOk(() => {
emits("delete", id);
});
}
const confirmBatchPhotoDelete = () => {
$q.dialog(confirmObject("Opravdu chces smazat vybrané fotky?"))
.onOk(() => {
for (const id in batchEdit.value) {
if (!batchEdit.value[id]) continue;
emits("delete", parseInt(id));
batchEdit.value[id] = false;
}
});
.onOk(() => {
for (const id in batchEdit.value) {
if (!batchEdit.value[id]) continue;
emits("delete", parseInt(id));
batchEdit.value[id] = false;
}
});
}
const handleImageClick = (photo, idx) => {
@@ -117,6 +117,13 @@ const batchOptionsProps = computed(() => ({
const setFlightCover = (titlePhoto) => {
emits("set-title-photo", titlePhoto);
}
const openPhoto = ref(false);
const photo = ref(null);
const showLarge = (displayedPhoto) => {
photo.value = displayedPhoto;
openPhoto.value = true;
}
</script>
<template>
@@ -124,12 +131,15 @@ const setFlightCover = (titlePhoto) => {
<div class="col-6 col-sm-4 col-md-4 col-lg-3" v-for="(photo, idx) in photos" :key="photo.id">
<q-card :class='{"q-ma-sm": true, "shadow-1": !batchEdit[photo.id], "shadow-10": batchEdit[photo.id]}'>
<q-img :src="photo.thumbnailUrl" @click="handleImageClick(photo, idx)" style="cursor: pointer">
<div class="absolute-top bg-transparent text-right">
<div class="absolute-top bg-transparent flex">
<div class="col-grow">
<q-btn icon="fullscreen" color="grey-6" round @click.stop.prevent="showLarge(photo)"/>
</div>
<q-btn
icon="star"
:color="titlePhoto?.id === photo.id ? 'amber-9' : 'grey-6'"
round
@click.stop.prevent="setFlightCover(photo)"
icon="star"
:color="titlePhoto?.id === photo.id ? 'amber-9' : 'grey-6'"
round
@click.stop.prevent="setFlightCover(photo)"
/>
</div>
@@ -146,9 +156,9 @@ const setFlightCover = (titlePhoto) => {
<q-card-actions align="right" :class="{'bg-primary': batchEdit[photo.id], 'text-white': batchEdit[photo.id]}" v-if="showActions">
<div class="col-grow">
<q-checkbox v-model="batchEdit[photo.id]"/>
<q-icon name="flight" v-if="photo.isAircraft" size="xs" color="grey-5" />
<q-icon name="person" v-if="photo.copilots.length > 0" size="xs" color="grey-5" />
<q-icon name="flight" v-if="photo.aircraftId" size="xs" color="grey-5"/>
<q-icon name="person" v-if="photo.copilots.length > 0" size="xs" color="grey-5"/>
<q-icon name="place" v-if="photo.pointOfInterest" size="xs" color="grey-5"/>
</div>
<q-btn flat icon="edit" color="blue" @click="openEdit(photo)"/>
<q-btn flat icon="tune" color="black" :to="{name: 'photoEditor', params: {id: photo.id}}"/>
@@ -169,4 +179,12 @@ const setFlightCover = (titlePhoto) => {
</q-card-actions>
</q-card>
</q-page-sticky>
<q-dialog v-model="openPhoto" full-width>
<q-img :src="photo.url">
<div class="absolute-top bg-transparent text-right">
<q-btn icon="close" round color="primary" @click="openPhoto = false" />
</div>
</q-img>
</q-dialog>
</template>
@@ -0,0 +1,7 @@
<script setup>
</script>
<template>
gallery skeleton
</template>
+13 -10
View File
@@ -4,7 +4,6 @@ import {commonProps} from "src/composables/inputs";
import {reactive, watch} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import AvatarFromPhoto from "components/avatars/AvatarFromPhoto.vue";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
user: {
@@ -12,7 +11,11 @@ const props = defineProps({
required: false,
default: null
},
isRequestPending
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
});
const formData = reactive({
avatarImage: null,
@@ -29,14 +32,14 @@ watch(() => props.user, (newVal) => {
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<div class="text-center">
<AvatarFromPhoto :size="200" :src="user.avatarImageUrl" v-if="user.avatarImageUrl" />
<AvatarFromPhoto :size="200" :src="user.avatarImageUrl" v-if="user.avatarImageUrl"/>
</div>
<q-file
v-model="formData.avatarImage"
accept="image/jpeg"
v-bind="commonProps"
label="Nahrát avatar"
v-model="formData.avatarImage"
accept="image/jpeg"
v-bind="commonProps"
label="Nahrát avatar"
>
<template #prepend>
<q-icon name="upload"/>
@@ -48,9 +51,9 @@ watch(() => props.user, (newVal) => {
</div>
<q-file
v-model="formData.titleImage"
accept="image/jpeg"
v-bind="commonProps" label="Nahrát titulní fotku"
v-model="formData.titleImage"
accept="image/jpeg"
v-bind="commonProps" label="Nahrát titulní fotku"
>
<template #prepend>
<q-icon name="upload"/>
+5 -2
View File
@@ -6,7 +6,6 @@ import {commonProps} from "src/composables/inputs";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
user: {
@@ -14,7 +13,11 @@ const props = defineProps({
required: false,
default: null
},
isRequestPending,
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
})