Newer
Older
import { useVModel, useWindowSize } from '@vueuse/core';
import type { IImage } from '@/app/interfaces/entities';
import { editEntity } from '@/app/helpers';
import { cropImage } from '@/app/helpers/images';
interface Props {
entityData: IImage;
}
const props = defineProps<Props>();
const emit = defineEmits(['update:entityData']);
const entityData = useVModel(props, 'entityData', emit);
const isModalCropImage = ref<boolean>(false);
const { width: windowWidth } = useWindowSize();
const textContainerWidth = computed(() => {
if (entityData.value?.paragraph_size === 'half')
return (windowWidth.value - 160 - entityData.value.image_width) / 2;
return windowWidth.value - 160 - entityData.value.image_width;
const editTitle = () => {
editEntity({ ...entityData.value, title: entityData.value.title });
};
editEntity({ ...entityData.value, text: entityData.value.text });
const saveImage = async (newUrl: string, newWidth: number, newHeight: number) => {
entityData.value.imageUrl = newUrl;
entityData.value.image_width = newWidth;
entityData.value.image_height = newHeight;
await cropImage(newUrl, entityData.value);
};
const scaleImage = (scale: string) => {
const initialWidth = Math.ceil(entityData.value.image_width / +entityData.value.image_scale);
entityData.value.image_width = initialWidth * +scale;
const initialHeight = Math.ceil(entityData.value.image_height / +entityData.value.image_scale);
entityData.value.image_height = initialHeight * +scale;
entityData.value.image_scale = scale;
editEntity({ ...entityData.value });
};
const openCropImageModal = () => (isModalCropImage.value = true);
</script>
<template>
<div
:class="[
'entityContainer relative flex py-8 px-16',
'justify-start': entityData.entity_position === 'left',
'justify-center': entityData.entity_position === 'center',
'justify-end': entityData.entity_position === 'right'
<CropImageModal
v-model:isVisible="isModalCropImage"
v-model:imageInfo="entityData"
@saveImage="saveImage"
/>
<EntityTitle
v-model:title="entityData.title"
:entityData="entityData"
@editTitle="editTitle"
<div class="flex gap-[32px]" :style="`height: ${entityData.image_height}px`">
<div
:class="[
'imageContainer relative leading-none min-h-[100px] min-w-[100px]',
{
'order-3': entityData.text_position === 'left'
}
]"
:style="`width: ${entityData.image_width}px; height: ${entityData.image_height}px`"
>
<img
:src="entityData?.imageUrl"
:alt="`Image ${entityData?.title}` || 'Image'"
:width="entityData.image_width"
:height="entityData.image_height"
class="'max-h-[700px] min-h-[100px] object-contain order-1'"
/>
<div class="speedDialSize absolute left-0 top-0 transition-all select-none">
<ImageSizeMenu :entityData="entityData" @scaleImage="scaleImage" />
v-if="entityData.text_position"
class="textContainer relative leading-none"
:style="`width: ${textContainerWidth}px; height: ${entityData.image_height}px`"
>
<textarea
ref="textarea"
v-model="entityData.text"
class="w-full indent-5 leading-normal overflow-auto resize-none outline-0 order-2"
placeholder="Enter text..."
rows="7"
:style="`font-size: ${entityData.font_size}px; height: ${entityData.image_height}px;`"
spellcheck="false"
<ImageMenu v-model:entityData="entityData" @openCropImageModal="openCropImageModal" />
.entityContainer .speedDial {
opacity: 0;
}
.entityContainer:hover .speedDial {
opacity: 100;
}
.imageContainer .speedDialSize {
opacity: 0;
}
.imageContainer:hover .speedDialSize {
opacity: 100;
}
input::placeholder {
font-weight: 400;
}
</style>