Skip to content
Snippets Groups Projects
ImageItem.vue 5.22 KiB
Newer Older
<script setup lang="ts">
import { useWindowSize } from '@vueuse/core';
import type { IImage } from '@/app/interfaces/entities';
import { editEntity } from '@/app/helpers';
import { cropImage } from '@/app/helpers/images';
import type { IEntity } from '@/app/interfaces/environment';
import { useDataStore } from '@/app/stores/data';

interface Props {
  entityData: IImage;
}
const props = defineProps<Props>();
const entityData = ref(props.entityData);

const dataStore = useDataStore();
const entities = computed(() => dataStore.entities);
const entityIndex = computed(() =>
  entities.value.findIndex((entity: IEntity) => entity.entity_uuid === props.entityData.entity_uuid)
);
const entitiesLength = computed(() => entities.value.length);

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 });
};
const editText = () => {
  editEntity({ ...entityData.value, text: entityData.value.text });
const saveChanges = (newState: IImage) => {
  editEntity(newState);
  entityData.value = newState;
};
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);
  isModalCropImage.value = false;
};
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);
      'entityContainer relative flex px-16 transition-all',
        '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"
    />
    <div class="flex flex-col">
      <EntityTitle
        v-model:title="entityData.title"
        :entityData="entityData"
        :isEditMode="isEditMode"
        @editTitle="editTitle"
      <div style="gap: 32px" class="flex" :style="`height: ${entityData.image_height}px`">
        <div
          :class="[
            'imageContainer relative leading-none',
            {
              'order-3': entityData.text_position === 'left'
            }
          ]"
          :style="`width: ${entityData.image_width}px; height: ${entityData.image_height}px; min-width: 100px; min-height: 100px`"
            :src="entityData?.imageUrl"
            :alt="`Image ${entityData?.title}` || 'Image'"
            :width="entityData.image_width"
            :height="entityData.image_height"
            style="min-height: 100px; max-height: 700px"
            class="object-contain order-1"
          <!--          <div class="speedDialSize absolute left-0 top-0 transition-all select-none">-->
          <!--            <ImageSizeMenu v-if="isEditMode" :entityData="entityData" @scaleImage="scaleImage" />-->
          <!--          </div>-->
          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',
              {
                'pointer-events-none': !isEditMode
              }
            ]"
            placeholder="Enter text..."
            rows="7"
            :style="`font-size: ${entityData.font_size}px; height: ${entityData.image_height}px;`"
            spellcheck="false"
      <ImageSettings v-if="isEditMode" :entityData="entityData" @saveChanges="saveChanges" />
      <EntityPositionSettings
        v-if="isEditMode && entitiesLength > 1"
        :entityUuid="entityData.entity_uuid"
        :entityIndex="entityIndex"
        :entitiesLength="entitiesLength"
.entityContainer:hover .aggregateHigh {
  height: 65px;
.entityContainer:hover .aggregateShort {
  height: 30px;
.entityContainer .speedDial {
  opacity: 0;
}
.entityContainer:hover .speedDial {
  opacity: 100;
}
.imageContainer .speedDialSize {
  opacity: 0;
}
.imageContainer:hover .speedDialSize {
  opacity: 100;
}
input::placeholder {
  font-weight: 400;
}
</style>