File size: 3,336 Bytes
755dd12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { RiArrowRightSLine, RiArrowDownSLine } from '@remixicon/vue';

interface IProps {
  sources?: Record<string, any>[];
  loading: boolean;
}

const { t } = useI18n();

const mediaRef = ref<HTMLDivElement | null>(null);
const unfold = ref(false);

const props = defineProps<IProps>();

const images = computed(() => {
  if (!props.sources) return [];
  if (props.sources.length <= 16) return props.sources;
  return props.sources.slice(0, 16);
});

const onFold = () => {
  if (!mediaRef.value) return;
  unfold.value = !unfold.value;
  if (unfold.value) {
    mediaRef.value.style.height = 'auto';
    mediaRef.value.style.overflow = 'normal';
  } else {
    mediaRef.value.style.height = '84px';
    mediaRef.value.style.overflow = 'hidden';
  }
};

onMounted(() => {
  //
});
const rowCol = [
  [
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' },
    { width: '12.5%', height: '64px', borderRadius: '6px' }
  ]
];
</script>

<script lang="ts">
export default {
  name: 'ChatMedia'
};
</script>

<template>
  <div class="w-full">
    <div class="flex flex-nowrap justify-between py-2">
      <div class="text-sm font-bold text-black dark:text-gray-300">
        {{ t('media') }}
      </div>
      <t-button variant="text" shape="square" :disabled="loading" @click="onFold">
        <template #icon>
          <RiArrowRightSLine v-if="!unfold" />
          <RiArrowDownSLine v-else />
        </template>
      </t-button>
    </div>
    <t-skeleton :row-col="rowCol" animation="flashed" :loading="!sources?.length && loading"></t-skeleton>
    <div v-if="sources?.length === 0 && !loading">
      <t-alert theme="info" :message="t('message.sourceError')" close>
        <template #operation>
        </template>
      </t-alert>
    </div>
    <div
      v-if="images.length"
      id="chat-media"
      ref="mediaRef"
      style="height: 84px; overflow: hidden;"
      class="grid w-full grid-cols-4 gap-2 transition-all duration-300 md:grid-cols-8"
    >
      <div v-for="item in images" :key="item.id" class="hover:opacity-80">
        <t-popup :content="item.name">
          <div class="flex flex-col gap-1">
            <t-image-viewer :close-on-overlay="true" :images="[item.img]">
              <template #trigger="{ open }">
                <t-image
                  :src="item.thumbnail"
                  :lazy="true"
                  fit="cover"
                  shape="round"
                  class="h-16"
                  @click="open"
                />
              </template>
            </t-image-viewer>
            <a :href="item.url" target="_blank" class="h-6 truncate text-zinc-600 hover:text-zinc-500 dark:text-zinc-400">
              {{ item.name }}
            </a>
          </div>
        </t-popup>
      </div>
    </div>
  </div>
</template>

<style scoped>
#chat-media {
  font-size: 12px;
}
</style>