Homepage, verejna cast, vetsi sada uprav a oprav

This commit is contained in:
Michal Kváček
2023-08-21 22:45:58 +02:00
parent 8bc477a611
commit 8c3b8d19dd
54 changed files with 550 additions and 372 deletions
+28
View File
@@ -0,0 +1,28 @@
<script setup>
const props = defineProps({
routeAdd: {
type: Object,
required: false
},
labelAdd: {
type: String,
required: false,
default: "Přidat"
}
});
</script>
<template>
<div class="q-pa-md q-gutter-sm">
<q-banner class="bg-light-blue text-white">
<template v-slot:avatar>
<q-icon name="info"/>
</template>
<slot/>
<template v-slot:action v-if="routeAdd">
<q-btn flat color="white" :to="routeAdd" :label="labelAdd"/>
</template>
</q-banner>
</div>
</template>
+1 -1
View File
@@ -47,7 +47,7 @@ const fullwidthBtn = computed(() => $q.screen.width <= $q.screen.sizes.md);
color="primary"
type="submit"
size="lg"
:class="{'q-my-lg': true, 'q-mx-lg': true, 'btn--fullwidth': fullwidthBtn}"
:class="{'q-my-lg': true, 'q-mx-lg': !fullwidthBtn, 'btn--fullwidth': fullwidthBtn}"
v-if="saveButton"
:icon="props.saveButton.icon"
:loading="props.isRequestPending"
+15
View File
@@ -0,0 +1,15 @@
<script setup>
import {randomInt} from "src/composables/random";
</script>
<template>
<q-item>
<q-item-section avatar>
<q-skeleton type="QAvatar" size="30px"/>
</q-item-section>
<q-item-section>
<q-skeleton type="text" :width="randomInt(50, 100)+'px'"/>
</q-item-section>
</q-item>
</template>
+6 -13
View File
@@ -1,10 +1,9 @@
<script setup>
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 {isRequired, maxLength, minLength} from "src/composables/form/rules";
import {isNumber, isRequired, maxLength, minLength} from "src/composables/form/rules";
import {commonProps} from "src/composables/inputs";
const formData = reactive({
@@ -24,14 +23,8 @@ const props = defineProps({
});
const rules = {
callSign: [
isRequired,
minLength(4),
maxLength(8)
],
seats: [
isNumber
]
callSign: [isRequired, minLength(4), maxLength(8)],
seats: [isRequired, isNumber]
};
onMounted(() => {
@@ -41,7 +34,7 @@ onMounted(() => {
</script>
<template>
<FormWrapper v-model="formData" :is-request-pending="isRequestPending">
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<q-img :src="props.defaultValues.photoUrl" v-if="props.defaultValues.photoUrl"/>
<q-input
@@ -67,8 +60,8 @@ onMounted(() => {
<q-input
type="number"
v-model="formData.seats"
label="Počet míst"
v-model.number="formData.seats"
label="Počet míst (včetně pilota)"
min="1"
:rules="rules.seats"
v-bind="commonProps"
+19 -10
View File
@@ -7,6 +7,11 @@ const props = defineProps({
flight: {
type: Object,
required: true
},
showCopilots: {
type: Boolean,
required: false,
default: false
}
})
</script>
@@ -70,16 +75,20 @@ const props = defineProps({
{{ minutesToHumanReadable(flight.durationMinCalculated) }}
</q-item-section>
</q-item>
<q-item v-if="flight.copilot">
<q-item-section avatar>
<q-icon name="people"/>
</q-item-section>
<q-item-section>
Link jen pro prihlasene!
<router-link :to="{name: 'copilotDetail', params: {id: flight.copilot.id}}">
{{ flight.copilot.name }}
</router-link>
</q-item-section>
<q-item v-if="flight.copilots?.length > 0">
<q-list>
<q-item v-for="copilot in flight.copilots" :key="copilot.id">
<q-item-section avatar>
<q-icon name="people"/>
</q-item-section>
<q-item-section>
<router-link :to="{name: 'copilotDetail', params: {id: copilot.id}}">
{{ copilot.name }}
</router-link>
</q-item-section>
</q-item>
</q-list>
</q-item>
</q-list>
</template>
@@ -1,3 +1,37 @@
<script setup>
import {randomInt} from "src/composables/random";
import ListItemSkeleton from "components/ListItemSkeleton.vue";
</script>
<template>
skeleton
<q-card class="flight-detail-card">
<q-skeleton animation="fade" height="400px" square/>
<q-card-section>
<q-list bordered separator>
<ListItemSkeleton/>
<ListItemSkeleton/>
<q-item>
<q-list>
<ListItemSkeleton v-for="i in randomInt(2, 5)" :key="i"/>
</q-list>
</q-item>
<ListItemSkeleton/>
<ListItemSkeleton/>
</q-list>
<article class="q-my-lg">
<q-skeleton
v-for="i in randomInt(5,8)" :key="i"
type="text" :width="randomInt(90, 100)+'%'"
/>
</article>
<q-skeleton height="400px" square class="q-mt-lg"/>
</q-card-section>
</q-card>
</template>
@@ -1,8 +1,8 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {commonProps} from "src/composables/inputs";
const props = defineProps({
flight: {
@@ -16,28 +16,27 @@ const props = defineProps({
});
const formData = reactive({
copilot: null,
copilots: [],
})
const solo = ref(true);
const solo = ref(false);
watch(() => solo.value, (newVal) => {
if (!newVal) {
formData.copilot = null;
formData.copilots = [];
}
});
onMounted(() => {
if (props.flight) {
setDefaultData(formData, props.flight);
solo.value = !formData.copilot;
}
})
watch(() => props.flight, (newVal) => {
if (newVal) {
formData.copilots = newVal.copilots.map(copilot => ({id: copilot.id, name: copilot.name}));
solo.value = formData.copilots.length === 0;
}
}, {deep: true, immediate: true});
</script>
<template>
<FormWrapper v-model="formData">
<q-btn-toggle
spread
no-caps
@@ -48,14 +47,13 @@ onMounted(() => {
<div v-if="!solo">
<ComboboxInput
class="q-my-lg"
outlined
standout
v-for="i in flight.aircraft.seats - 1"
:key="i"
v-bind="commonProps"
:options="copilots"
v-model="formData.copilot"
:key="formData.copilot"
v-model="formData.copilots[i-1]"
:clearable="true"
label="Druhy pilot"
:label="i === 1 ? 'Kopilot' : 'Pasažér'"
/>
</div>
+1 -1
View File
@@ -94,7 +94,7 @@ const filterFn = (val, update, abort) => {
:v-bind="$attrs"
>
<template v-slot:no-option>
<q-item>
<q-item v-if="inputValue">
<q-item-section avatar>
<q-avatar text-color="green" size="32px" icon="add" />
</q-item-section>
+1
View File
@@ -27,6 +27,7 @@ watch(
map.fitBounds(bounds);
}
);
</script>
<template>
+40 -40
View File
@@ -64,47 +64,48 @@ const showExtra = ref(false);
@keyup.right="nextPhoto"
>
<q-card-section>
<div class="row">
<div class="col-12">
<div class="text-center">
<inner-image-zoom move-type="pan" :zoomScale="0.75" :hide-hint="true" :src="photo.url"/>
</div>
<q-btn
class="absolute all-pointer-events"
round
flat
icon="info"
:text-color="showExtra ? 'primary' : 'white'"
style="background: rgba(0, 0, 0, 0.25); top: 8px; right: 8px"
@click="showExtra = !showExtra"
/>
<q-btn
class="absolute all-pointer-events"
style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;"
@click="prevPhoto"
v-if="photoIndex > 0"
icon="chevron_left"
text-color="white"
flat
rounded
>
</q-btn>
<q-btn
class="absolute all-pointer-events"
style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;"
@click="nextPhoto"
v-if="photoIndex < photos.length - 1"
icon-right="chevron_right"
text-color="white"
flat
rounded
>
</q-btn>
<strong v-if="photo.name !== ''">{{ photo.name }}</strong>
<p v-if="photo.description !== ''">{{ photo.description }}</p>
<div class="relative-position">
<div class="text-center">
<inner-image-zoom move-type="pan" :zoomScale="0.75" :hide-hint="true" :src="photo.url"/>
</div>
<q-btn
class="absolute all-pointer-events"
round
flat
icon="info"
:text-color="showExtra ? 'primary' : 'white'"
style="background: rgba(0, 0, 0, 0.25); top: 8px; right: 8px"
@click="showExtra = !showExtra"
/>
<q-btn
class="absolute all-pointer-events"
style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;"
@click="prevPhoto"
v-if="photoIndex > 0"
icon="chevron_left"
text-color="white"
flat
rounded
>
</q-btn>
<q-btn
class="absolute all-pointer-events"
style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;"
@click="nextPhoto"
v-if="photoIndex < photos.length - 1"
icon-right="chevron_right"
text-color="white"
flat
rounded
>
</q-btn>
<strong v-if="photo.name !== ''">{{ photo.name }}</strong>
<p v-if="photo.description !== ''">{{ photo.description }}</p>
</div>
<div class="row">
<div class="col-12 q-my-md" v-if="showExtra">
<EmbeddedMap
v-if="photo.gpsLatitude && photo.gpsLongitude"
@@ -150,7 +151,6 @@ const showExtra = ref(false);
<style>
.iiz {
width: 100%;
height: 90vh;
}
.iiz__img {
+7 -3
View File
@@ -3,6 +3,7 @@ import {computed, ref} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import DialogWrapper from "components/DialogWrapper.vue";
import FormWrapper from "components/FormWrapper.vue";
import {commonProps} from "src/composables/inputs";
const props = defineProps({
photo: {
@@ -32,8 +33,10 @@ const setup = (() => {
<q-card-section>
<FormWrapper :save-button="false">
<q-input v-model="formData.name" label="Název"/>
<q-input type="textarea" v-model="formData.description" label="Popis"/>
<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"/>
{{ locations }}
<q-select
:options="locations"
@@ -41,11 +44,12 @@ const setup = (() => {
option-value="id"
emit-value
map-options
v-bind="commonProps"
v-model="formData.pointOfInterestId"
label="POI"
/>
<q-checkbox v-model="formData.isFlightCover" label="Úvodní fotografie k letu?" />
<q-checkbox v-model="formData.isFlightCover" label="Úvodní fotografie k letu?"/>
</FormWrapper>
</q-card-section>
</DialogWrapper>
@@ -0,0 +1,22 @@
<script setup>
import {user as pilot} from "src/composables/objects/user";
import {FORMAT_DATE, formatDatetime} from "src/composables/datetimeUtils";
import AvatarFromPhoto from "components/AvatarFromPhoto.vue";
</script>
<template>
<q-card flat style="margin: 0 auto; max-width: 400px">
<q-img :src="pilot.titleImageUrl" v-if="pilot.titleImageUrl"/>
<q-card-section>
<div class="text-center" :style="`margin-top: ${pilot.titleImageUrl ? '-100' : '0'}px`">
<AvatarFromPhoto :size="150" :src="pilot.avatarImageUrl" v-if="pilot.avatarImageUrl" class="q-mb-sm"/>
<div class="text-h3">{{ pilot.name }}</div>
<div class="text-subtitle1 text-weight-thin">
Registrován: {{ formatDatetime(pilot.createdAt, FORMAT_DATE) }}
</div>
</div>
<div class="q-my-lg" v-html="pilot.description"/>
</q-card-section>
</q-card>
</template>
+2 -1
View File
@@ -4,6 +4,7 @@ import {commonProps} from "src/composables/inputs";
import {reactive, watch} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import AvatarFromPhoto from "components/AvatarFromPhoto.vue";
import {user as pilot} from "src/composables/objects/user";
const props = defineProps({
user: {
@@ -27,7 +28,7 @@ watch(() => props.user, (newVal) => {
<FormWrapper v-model="formData">
<div class="text-center">
<AvatarFromPhoto :size="200" :src="user.avatarImageUrl" />
<AvatarFromPhoto :size="200" :src="user.avatarImageUrl" v-if="user.avatarImageUrl" />
</div>
<q-file
+15 -13
View File
@@ -26,19 +26,21 @@ watch(() => props.user, (newVal) => {
</script>
<template>
<q-list>
<q-item v-if="user.publicUsername">
<router-link target="_blank" :to="{name: 'publicProfileDetail', params: {username: user.publicUsername}}">
@{{user.publicUsername}}
</router-link>
</q-item>
<q-item v-else>
<q-icon name="" color="red" /> Nastav si veřejné uživatelské jméno pro zpřístupnění profilu a sdílení záznamů s ostatními
</q-item>
</q-list>
<FormWrapper v-model="formData">
<q-input v-model="formData.name" label="Jméno" v-bind="commonProps"/>
<q-list>
<q-item v-if="user.publicUsername">
<router-link target="_blank" :to="{name: 'publicProfileDetail', params: {username: user.publicUsername}}">
@{{ user.publicUsername }}
</router-link>
</q-item>
<q-item v-else>
<q-icon name="" color="red"/>
Nastav si veřejné uživatelské jméno pro zpřístupnění profilu a sdílení záznamů s ostatními
</q-item>
</q-list>
<q-input v-model="formData.name" label="Jméno" v-bind="commonProps"/>
<q-input
v-model="formData.publicUsername"
label="Veřejné uživatelské jméno"
@@ -46,6 +48,6 @@ watch(() => props.user, (newVal) => {
v-bind="commonProps"
/>
<RichTextEditor v-model="formData.description" label="Veřejný podpis" />
<RichTextEditor v-model="formData.description" label="Veřejný podpis"/>
</FormWrapper>
</template>
@@ -0,0 +1,3 @@
<script setup> </script>
<template>Skeleton</template>