EventImageModal feature
This commit is contained in:
parent
deee3ed673
commit
ef890fb577
src/components/Event
65
src/components/Event/EventImageModal.vue
Normal file
65
src/components/Event/EventImageModal.vue
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<div class="modal-overlay" @click.self="closeModal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<img :src="image" alt="Full-size event banner" />
|
||||||
|
<button class="close-button" @click="closeModal">X</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
image: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed !important;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1000000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
position: relative;
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.modal-content {
|
||||||
|
max-width: 80%;
|
||||||
|
max-height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -154,13 +154,32 @@
|
||||||
>
|
>
|
||||||
<span v-else>{{ extra.value }}</span>
|
<span v-else>{{ extra.value }}</span>
|
||||||
</event-metadata-block>
|
</event-metadata-block>
|
||||||
|
<event-metadata-block
|
||||||
|
v-if="isUserUploadedImage"
|
||||||
|
:title="t('Title Picture')"
|
||||||
|
>
|
||||||
|
<!-- Event Banner Component, only displayed if user uploaded image -->
|
||||||
|
<div class="clickable-banner" @click="showBannerFullScreen">
|
||||||
|
<event-banner :picture="event.picture" />
|
||||||
|
</div>
|
||||||
|
</event-metadata-block>
|
||||||
|
|
||||||
|
<!-- Modal to display full-screen image -->
|
||||||
|
<Teleport to=body>
|
||||||
|
<event-image-modal
|
||||||
|
v-if="showFullScreen"
|
||||||
|
:image="event.picture.url"
|
||||||
|
@close="showFullScreen = false"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Address, addressToPoiInfos } from "@/types/address.model";
|
import { Address, addressToPoiInfos } from "@/types/address.model";
|
||||||
import { EventMetadataKeyType, EventMetadataType } from "@/types/enums";
|
import { EventMetadataKeyType, EventMetadataType } from "@/types/enums";
|
||||||
import { IEvent } from "@/types/event.model";
|
import { IEvent } from "@/types/event.model";
|
||||||
import { computed } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import RouteName from "../../router/name";
|
import RouteName from "../../router/name";
|
||||||
import { usernameWithDomain } from "../../types/actor";
|
import { usernameWithDomain } from "../../types/actor";
|
||||||
import EventMetadataBlock from "./EventMetadataBlock.vue";
|
import EventMetadataBlock from "./EventMetadataBlock.vue";
|
||||||
|
@ -174,6 +193,8 @@ import { useI18n } from "vue-i18n";
|
||||||
import Earth from "vue-material-design-icons/Earth.vue";
|
import Earth from "vue-material-design-icons/Earth.vue";
|
||||||
import Calendar from "vue-material-design-icons/Calendar.vue";
|
import Calendar from "vue-material-design-icons/Calendar.vue";
|
||||||
import Link from "vue-material-design-icons/Link.vue";
|
import Link from "vue-material-design-icons/Link.vue";
|
||||||
|
import EventBanner from "@/components/Event/EventBanner.vue";
|
||||||
|
import EventImageModal from "@/components/Event/EventImageModal.vue";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -242,7 +263,22 @@ const accountURL = (extra: IEventMetadataDescription): string | undefined => {
|
||||||
const userTimezone = computed((): string | undefined => {
|
const userTimezone = computed((): string | undefined => {
|
||||||
return props.user?.settings?.timezone;
|
return props.user?.settings?.timezone;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** Define the default image URL */
|
||||||
|
const DEFAULT_CARD_URL = "/img/mobilizon_default_card.png";
|
||||||
|
|
||||||
|
/** Computed property to check if the image is a user-uploaded image */
|
||||||
|
const isUserUploadedImage = computed(() => {
|
||||||
|
return props.event.picture?.url && props.event.picture.url !== DEFAULT_CARD_URL;
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Handle click to show banner in full-screen */
|
||||||
|
const showFullScreen = ref(false);
|
||||||
|
const showBannerFullScreen = () => {
|
||||||
|
showFullScreen.value = true; // Open full-screen modal
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.metadata-organized-by) {
|
:deep(.metadata-organized-by) {
|
||||||
.v-popover.popover .trigger {
|
.v-popover.popover .trigger {
|
||||||
|
@ -272,4 +308,19 @@ div.address-wrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clickable-banner {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
max-height: 150px; /* Constrain image size */
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
object-fit: contain;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
object-fit: cover; /* Ensure the image fits within the constrained area */
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue