Simula_r
2025-10-02 13:58:47 -07:00
committed by GitHub
parent 3818ba5d17
commit 0d3d258995
13 changed files with 370 additions and 43 deletions

View File

@@ -29,6 +29,7 @@ interface Props {
uploadable?: boolean
disabled?: boolean
accept?: string
filterOptions?: FilterOption[]
sortOptions?: SortOption[]
isSelected?: (
@@ -195,6 +196,7 @@ function handleSelection(item: DropdownItem, index: number) {
:selected="selected"
:uploadable="uploadable"
:disabled="disabled"
:accept="accept"
@select-click="toggleDropdown"
@file-change="handleFileChange"
/>

View File

@@ -15,6 +15,7 @@ interface Props {
maxSelectable: number
uploadable: boolean
disabled: boolean
accept?: string
}
const props = withDefaults(defineProps<Props>(), {
@@ -92,6 +93,7 @@ const theButtonStyle = computed(() => [
class="opacity-0 absolute inset-0 -z-1"
:multiple="maxSelectable > 1"
:disabled="disabled"
:accept="accept"
@change="emit('file-change', $event)"
/>
</label>

View File

@@ -84,7 +84,7 @@ const searchQuery = defineModel<string>('searchQuery')
:key="item.id"
:index="index"
:selected="isSelected(item, index)"
:image-src="item.imageSrc"
:media-src="item.mediaSrc"
:name="item.name"
:metadata="item.metadata"
:layout="layoutMode"

View File

@@ -1,14 +1,14 @@
<script setup lang="ts">
import { ref } from 'vue'
import { computed, inject, ref } from 'vue'
import { cn } from '@/utils/tailwindUtil'
import type { LayoutMode } from './types'
import { AssetKindKey, type LayoutMode } from './types'
interface Props {
index: number
selected: boolean
imageSrc: string
mediaSrc: string
name: string
metadata?: string
layout?: LayoutMode
@@ -18,23 +18,36 @@ const props = defineProps<Props>()
const emit = defineEmits<{
click: [index: number]
imageLoad: [event: Event]
mediaLoad: [event: Event]
}>()
const actualDimensions = ref<string | null>(null)
const assetKind = inject(AssetKindKey)
const isVideo = computed(() => assetKind?.value === 'video')
function handleClick() {
emit('click', props.index)
}
function handleImageLoad(event: Event) {
emit('imageLoad', event)
emit('mediaLoad', event)
if (!event.target || !(event.target instanceof HTMLImageElement)) return
const img = event.target
if (img.naturalWidth && img.naturalHeight) {
actualDimensions.value = `${img.naturalWidth} x ${img.naturalHeight}`
}
}
function handleVideoLoad(event: Event) {
emit('mediaLoad', event)
if (!event.target || !(event.target instanceof HTMLVideoElement)) return
const video = event.target
if (video.videoWidth && video.videoHeight) {
actualDimensions.value = `${video.videoWidth} x ${video.videoHeight}`
}
}
</script>
<template>
@@ -81,9 +94,17 @@ function handleImageLoad(event: Event) {
>
<i-lucide:check class="size-3 text-white -translate-y-[0.5px]" />
</div>
<video
v-if="mediaSrc && isVideo"
:src="mediaSrc"
class="size-full object-cover"
preload="metadata"
muted
@loadeddata="handleVideoLoad"
/>
<img
v-if="imageSrc"
:src="imageSrc"
v-else-if="mediaSrc"
:src="mediaSrc"
class="size-full object-cover"
@load="handleImageLoad"
/>

View File

@@ -1,9 +1,13 @@
import type { ComputedRef, InjectionKey } from 'vue'
import type { AssetKind } from '@/types/widgetTypes'
export type OptionId = string | number | symbol
export type SelectedKey = OptionId
export interface DropdownItem {
id: SelectedKey
imageSrc: string
mediaSrc: string // URL for image, video, or other media
name: string
metadata: string
}
@@ -19,3 +23,6 @@ export interface FilterOption {
}
export type LayoutMode = 'list' | 'grid' | 'list-small'
export const AssetKindKey: InjectionKey<ComputedRef<AssetKind | undefined>> =
Symbol('assetKind')