💄 Optimized attachments view
This commit is contained in:
		@@ -3,33 +3,53 @@
 | 
			
		||||
    Attached {{ props.attachments.length }} attachment(s)
 | 
			
		||||
  </v-chip>
 | 
			
		||||
 | 
			
		||||
  <v-card v-else variant="outlined" class="max-w-[540px] max-h-[720px]">
 | 
			
		||||
    <v-carousel hide-delimiter-background height="100%" :show-arrows="false">
 | 
			
		||||
      <v-carousel-item v-for="item in attachments">
 | 
			
		||||
        <img v-if="item.type === 1" :src="getUrl(item)" :alt="item.filename" class="cursor-zoom-in"
 | 
			
		||||
             @click="openLightbox" />
 | 
			
		||||
        <video v-if="item.type === 2" controls class="w-full">
 | 
			
		||||
          <source :src="getUrl(item)" />
 | 
			
		||||
        </video>
 | 
			
		||||
        <div v-if="item.type === 3" class="w-full px-7 py-12">
 | 
			
		||||
          <audio controls :src="getUrl(item)" class="mx-auto"></audio>
 | 
			
		||||
        </div>
 | 
			
		||||
      </v-carousel-item>
 | 
			
		||||
    </v-carousel>
 | 
			
		||||
  <v-responsive v-else :aspect-ratio="16 / 9" max-height="720">
 | 
			
		||||
    <v-card variant="outlined" class="w-full h-full">
 | 
			
		||||
      <v-carousel
 | 
			
		||||
        hide-delimiter-background
 | 
			
		||||
        height="100%"
 | 
			
		||||
        :hide-delimiters="props.attachments.length <= 1"
 | 
			
		||||
        :show-arrows="false"
 | 
			
		||||
      >
 | 
			
		||||
        <v-carousel-item v-for="(item, idx) in attachments">
 | 
			
		||||
          <img
 | 
			
		||||
            v-if="item.type === 1"
 | 
			
		||||
            loading="lazy"
 | 
			
		||||
            decoding="async"
 | 
			
		||||
            class="cursor-zoom-in content-visibility-auto"
 | 
			
		||||
            :src="getUrl(item)"
 | 
			
		||||
            :alt="item.filename"
 | 
			
		||||
            @click="openLightbox(item, idx)"
 | 
			
		||||
          />
 | 
			
		||||
          <video v-if="item.type === 2" controls class="w-full content-visibility-auto">
 | 
			
		||||
            <source :src="getUrl(item)" />
 | 
			
		||||
          </video>
 | 
			
		||||
          <div v-if="item.type === 3" class="w-full px-7 py-12">
 | 
			
		||||
            <audio controls :src="getUrl(item)" class="mx-auto"></audio>
 | 
			
		||||
          </div>
 | 
			
		||||
        </v-carousel-item>
 | 
			
		||||
      </v-carousel>
 | 
			
		||||
 | 
			
		||||
    <vue-easy-lightbox teleport="#app" :visible="lightbox" :imgs="[getUrl(current)]" @hide="lightbox = false">
 | 
			
		||||
      <template v-slot:close-btn="{ close }">
 | 
			
		||||
        <v-btn
 | 
			
		||||
          class="fixed left-2 top-2"
 | 
			
		||||
          icon="mdi-close"
 | 
			
		||||
          variant="text"
 | 
			
		||||
          color="white"
 | 
			
		||||
          :style="`margin-top: ${safeAreaTop}`"
 | 
			
		||||
          @click="close"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </vue-easy-lightbox>
 | 
			
		||||
  </v-card>
 | 
			
		||||
      <vue-easy-lightbox
 | 
			
		||||
        teleport="#app"
 | 
			
		||||
        :visible="lightbox"
 | 
			
		||||
        :imgs="props.attachments.map((x) => getUrl(x))"
 | 
			
		||||
        v-model:index="currentIndex"
 | 
			
		||||
        @hide="lightbox = false"
 | 
			
		||||
      >
 | 
			
		||||
        <template v-slot:close-btn="{ close }">
 | 
			
		||||
          <v-btn
 | 
			
		||||
            class="fixed left-2 top-2"
 | 
			
		||||
            icon="mdi-close"
 | 
			
		||||
            variant="text"
 | 
			
		||||
            color="white"
 | 
			
		||||
            :style="`margin-top: ${safeAreaTop}`"
 | 
			
		||||
            @click="close"
 | 
			
		||||
          />
 | 
			
		||||
        </template>
 | 
			
		||||
      </vue-easy-lightbox>
 | 
			
		||||
    </v-card>
 | 
			
		||||
  </v-responsive>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
@@ -43,23 +63,24 @@ const props = defineProps<{ attachments: any[]; overview?: boolean }>()
 | 
			
		||||
const ui = useUI()
 | 
			
		||||
 | 
			
		||||
const lightbox = ref(false)
 | 
			
		||||
const focus = ref(0)
 | 
			
		||||
 | 
			
		||||
const current = computed(() => props.attachments[focus.value])
 | 
			
		||||
const canLightbox = computed(() => current.value.type === 1)
 | 
			
		||||
const current = ref<any>(null)
 | 
			
		||||
const currentIndex = ref(0)
 | 
			
		||||
 | 
			
		||||
const safeAreaTop = computed(() => {
 | 
			
		||||
  return `${ui.safeArea.top}px`
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function getUrl(item: any) {
 | 
			
		||||
  return item.external_url ? item.external_url : buildRequestUrl("interactive", `/api/attachments/o/${item.file_id}`)
 | 
			
		||||
  return item.external_url
 | 
			
		||||
    ? item.external_url
 | 
			
		||||
    : buildRequestUrl("interactive", `/api/attachments/o/${item.file_id}`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function openLightbox() {
 | 
			
		||||
  if (canLightbox.value) {
 | 
			
		||||
    lightbox.value = true
 | 
			
		||||
  }
 | 
			
		||||
function openLightbox(item: any, idx: number) {
 | 
			
		||||
  current.value = item
 | 
			
		||||
  currentIndex.value = idx
 | 
			
		||||
  lightbox.value = true
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,13 +11,13 @@
 | 
			
		||||
  >
 | 
			
		||||
    <div class="flex flex-col h-full">
 | 
			
		||||
      <v-toolbar
 | 
			
		||||
        class="flex items-center justify-between px-[12px] border-opacity-15"
 | 
			
		||||
        class="flex items-center justify-between px-[14px] border-opacity-15"
 | 
			
		||||
        color="primary"
 | 
			
		||||
        height="64"
 | 
			
		||||
        :style="`padding-top: ${safeAreaTop}`"
 | 
			
		||||
      >
 | 
			
		||||
        <div class="flex items-center">
 | 
			
		||||
          <img src="/favicon.png" alt="Logo" width="36" height="36" class="block" />
 | 
			
		||||
          <img src="/favicon.png" alt="Logo" width="32" height="32" class="block" />
 | 
			
		||||
          <div v-show="!drawerMini" class="ms-6 font-medium">Solar Network</div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user