|
|
|
@ -6,21 +6,17 @@ import { useSortable } from './sort'
|
|
|
|
|
import Carousel from './Carousel.vue' |
|
|
|
|
import { onMounted, ref, useDropZone, watch } from '#imports' |
|
|
|
|
import { isImage, openLink } from '~/utils' |
|
|
|
|
import MaterialSymbolsAttachFile from '~icons/material-symbols/attach-file' |
|
|
|
|
import MaterialArrowExpandIcon from '~icons/mdi/arrow-expand' |
|
|
|
|
import MaterialSymbolsFileCopyOutline from '~icons/material-symbols/file-copy-outline' |
|
|
|
|
import MdiReload from '~icons/mdi/reload' |
|
|
|
|
import IcOutlineInsertDriveFile from '~icons/ic/outline-insert-drive-file' |
|
|
|
|
|
|
|
|
|
interface Props { |
|
|
|
|
modelValue: string | Record<string, any>[] | null |
|
|
|
|
rowIndex: number |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
interface Emits { |
|
|
|
|
(event: 'update:modelValue', value: string | Record<string, any>): void |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { modelValue } = defineProps<Props>() |
|
|
|
|
const { modelValue, rowIndex } = defineProps<Props>() |
|
|
|
|
|
|
|
|
|
const emits = defineEmits<Emits>() |
|
|
|
|
|
|
|
|
@ -60,7 +56,7 @@ onKeyDown('Escape', () => {
|
|
|
|
|
/** if possible, on mounted we try to fetch the relevant `td` cell to use as a dropzone */ |
|
|
|
|
onMounted(() => { |
|
|
|
|
if (typeof document !== 'undefined') { |
|
|
|
|
dropZoneRef.value = document.querySelector(`td[data-col="${column.value.id}"]`) as HTMLTableDataCellElement |
|
|
|
|
dropZoneRef.value = document.querySelector(`td[data-key="${rowIndex}${column.value.id}"]`) as HTMLTableDataCellElement |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
</script> |
|
|
|
@ -73,7 +69,7 @@ onMounted(() => {
|
|
|
|
|
<general-overlay |
|
|
|
|
v-model="isOverDropZone" |
|
|
|
|
inline |
|
|
|
|
:target="`td[data-col='${column.id}']`" |
|
|
|
|
:target="`td[data-key='${rowIndex}${column.id}']`" |
|
|
|
|
class="text-white text-lg ring ring-pink-500 bg-gray-700/75 flex items-center justify-center gap-2 backdrop-blur-xl" |
|
|
|
|
> |
|
|
|
|
<MaterialSymbolsFileCopyOutline class="text-pink-500" /> Drop here |
|
|
|
@ -100,12 +96,15 @@ onMounted(() => {
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<template v-if="visibleItems.length"> |
|
|
|
|
<div ref="sortableRef" :class="{ dragging }" class="flex flex-wrap gap-2 p-1 scrollbar-thin-dull"> |
|
|
|
|
<div |
|
|
|
|
ref="sortableRef" |
|
|
|
|
:class="{ dragging }" |
|
|
|
|
class="flex justify-center items-center flex-wrap gap-2 p-1 scrollbar-thin-dull max-h-[150px] overflow-scroll" |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
v-for="(item, i) of visibleItems" |
|
|
|
|
:id="item.url" |
|
|
|
|
:key="item.url || item.title" |
|
|
|
|
style="flex: 1 1 50px" |
|
|
|
|
:class="isImage(item.title, item.mimetype) ? '' : 'border-1 rounded'" |
|
|
|
|
class="nc-attachment flex items-center justify-center min-h-[50px]" |
|
|
|
|
> |
|
|
|
@ -120,7 +119,7 @@ onMounted(() => {
|
|
|
|
|
placeholder |
|
|
|
|
:alt="item.title || `#${i}`" |
|
|
|
|
:src="item.url || item.data" |
|
|
|
|
class="ring-1 ring-gray-300 rounded" |
|
|
|
|
class="ring-1 ring-gray-300 rounded max-h-[50px] max-w-[50px]" |
|
|
|
|
@click="selectedImage = item" |
|
|
|
|
/> |
|
|
|
|
|
|
|
|
@ -137,10 +136,7 @@ onMounted(() => {
|
|
|
|
|
<a-tooltip v-else placement="bottom"> |
|
|
|
|
<template #title> View attachments </template> |
|
|
|
|
|
|
|
|
|
<MaterialArrowExpandIcon |
|
|
|
|
class="select-none transform group-hover:(text-pink-500 scale-120)" |
|
|
|
|
@click.stop="modalVisible = true" |
|
|
|
|
/> |
|
|
|
|
<MdiArrowExpand class="select-none transform group-hover:(text-pink-500 scale-120)" @click.stop="modalVisible = true" /> |
|
|
|
|
</a-tooltip> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
@ -152,6 +148,10 @@ onMounted(() => {
|
|
|
|
|
<style lang="scss"> |
|
|
|
|
.nc-cell { |
|
|
|
|
.nc-attachment-cell { |
|
|
|
|
.nc-attachment { |
|
|
|
|
@apply w-[50px] h-[50px] min-h-[50px] min-w-[50px]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.ghost, |
|
|
|
|
.ghost > * { |
|
|
|
|
@apply !pointer-events-none; |
|
|
|
|