Skip to content

Commit 7a0302b

Browse files
authored
Enhance MediaAssetCard selection UI and interaction (#6729)
1 parent a4d979e commit 7a0302b

File tree

6 files changed

+45
-39
lines changed

6 files changed

+45
-39
lines changed

src/components/sidebar/tabs/AssetsSidebarTab.vue

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
/>
6868
</div>
6969
<!-- Content -->
70-
<div v-else class="relative size-full">
70+
<div v-else class="relative size-full" @click="handleEmptySpaceClick">
7171
<VirtualGrid
7272
:items="mediaAssetsWithKey"
7373
:grid-style="{
@@ -97,32 +97,22 @@
9797
<template #footer>
9898
<div
9999
v-if="hasSelection"
100-
class="flex h-18 w-full items-center justify-between px-4"
100+
class="flex gap-1 h-18 w-full items-center justify-between"
101101
>
102-
<div>
102+
<div ref="selectionCountButtonRef" class="flex-1 pl-4">
103103
<TextButton
104-
v-if="isHoveringSelectionCount"
105-
:label="$t('mediaAsset.selection.deselectAll')"
104+
:label="
105+
isHoveringSelectionCount
106+
? $t('mediaAsset.selection.deselectAll')
107+
: $t('mediaAsset.selection.selectedCount', {
108+
count: totalOutputCount
109+
})
110+
"
106111
type="transparent"
107112
@click="handleDeselectAll"
108-
@mouseleave="isHoveringSelectionCount = false"
109113
/>
110-
<span
111-
v-else
112-
role="button"
113-
tabindex="0"
114-
:aria-label="$t('mediaAsset.selection.deselectAll')"
115-
class="cursor-pointer px-3 text-sm focus:ring-2 focus:ring-primary focus:outline-none"
116-
@mouseenter="isHoveringSelectionCount = true"
117-
@keydown.enter="handleDeselectAll"
118-
@keydown.space.prevent="handleDeselectAll"
119-
>
120-
{{
121-
$t('mediaAsset.selection.selectedCount', { count: selectedCount })
122-
}}
123-
</span>
124114
</div>
125-
<div class="flex gap-2">
115+
<div class="flex gap-2 pr-4">
126116
<IconTextButton
127117
v-if="shouldShowDeleteButton"
128118
:label="$t('mediaAsset.selection.deleteSelected')"
@@ -155,7 +145,7 @@
155145
</template>
156146

157147
<script setup lang="ts">
158-
import { useDebounceFn } from '@vueuse/core'
148+
import { useDebounceFn, useElementHover } from '@vueuse/core'
159149
import ProgressSpinner from 'primevue/progressspinner'
160150
import { useToast } from 'primevue/usetoast'
161151
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
@@ -223,7 +213,6 @@ const {
223213
isSelected,
224214
handleAssetClick,
225215
hasSelection,
226-
selectedCount,
227216
clearSelection,
228217
getSelectedAssets,
229218
activate: activateSelection,
@@ -232,8 +221,15 @@ const {
232221
233222
const { downloadMultipleAssets, deleteMultipleAssets } = useMediaAssetActions()
234223
235-
// Hover state for selection count
236-
const isHoveringSelectionCount = ref(false)
224+
// Hover state for selection count button
225+
const selectionCountButtonRef = ref<HTMLElement | null>(null)
226+
const isHoveringSelectionCount = useElementHover(selectionCountButtonRef)
227+
228+
// Total output count for all selected assets
229+
const totalOutputCount = computed(() => {
230+
const selectedAssets = getSelectedAssets(displayAssets.value)
231+
return selectedAssets.reduce((sum, asset) => sum + getOutputCount(asset), 0)
232+
})
237233
238234
const currentAssets = computed(() =>
239235
activeTab.value === 'input' ? inputAssets : outputAssets
@@ -400,7 +396,6 @@ const exitFolderView = () => {
400396
folderExecutionTime.value = undefined
401397
folderAssets.value = []
402398
searchQuery.value = ''
403-
clearSelection()
404399
}
405400
406401
onMounted(() => {
@@ -413,7 +408,12 @@ onUnmounted(() => {
413408
414409
const handleDeselectAll = () => {
415410
clearSelection()
416-
isHoveringSelectionCount.value = false
411+
}
412+
413+
const handleEmptySpaceClick = () => {
414+
if (hasSelection) {
415+
clearSelection()
416+
}
417417
}
418418
419419
const copyJobId = async () => {
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<template>
22
<div class="relative size-full overflow-hidden rounded">
33
<div
4-
class="flex size-full flex-col items-center justify-center gap-2 bg-modal-card-placeholder-background text-base-foreground"
4+
class="flex size-full flex-col items-center justify-center gap-2 bg-modal-card-placeholder-background transition-transform duration-300 group-hover:scale-105 group-data-[selected=true]:scale-105"
55
>
6-
<i class="icon-[lucide--box] text-3xl" />
7-
<span>{{ $t('assetBrowser.media.threeDModelPlaceholder') }}</span>
6+
<i class="icon-[lucide--box] text-3xl text-base-foreground" />
7+
<span class="text-base-foreground">{{
8+
$t('assetBrowser.media.threeDModelPlaceholder')
9+
}}</span>
810
</div>
911
</div>
1012
</template>

src/platform/assets/components/MediaAssetCard.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
variant="ghost"
1616
rounded="lg"
1717
:class="containerClasses"
18+
:data-selected="selected"
19+
@click.stop
1820
>
1921
<template #top>
2022
<CardTop
@@ -247,10 +249,10 @@ provide(MediaAssetKey, {
247249
248250
const containerClasses = computed(() =>
249251
cn(
250-
'gap-1 select-none',
252+
'gap-1 select-none group',
251253
selected
252-
? 'border-3 border-base-foreground bg-modal-card-background'
253-
: 'hover:bg-modal-card-background/70'
254+
? 'ring-3 ring-inset ring-base-foreground bg-modal-card-background'
255+
: 'hover:bg-modal-card-background'
254256
)
255257
)
256258

src/platform/assets/components/MediaAudioTop.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<template>
22
<div class="relative size-full overflow-hidden rounded">
33
<div
4-
class="flex size-full flex-col items-center justify-center gap-2 bg-modal-card-placeholder-background text-base-foreground"
4+
class="flex size-full flex-col items-center justify-center gap-2 bg-modal-card-placeholder-background transition-transform duration-300 group-hover:scale-105 group-data-[selected=true]:scale-105"
55
>
6-
<i class="icon-[lucide--music] text-3xl" />
7-
<span>{{ $t('assetBrowser.media.audioPlaceholder') }}</span>
6+
<i class="icon-[lucide--music] text-3xl text-base-foreground" />
7+
<span class="text-base-foreground">{{
8+
$t('assetBrowser.media.audioPlaceholder')
9+
}}</span>
810
</div>
911
<audio
1012
controls

src/platform/assets/components/MediaImageTop.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
v-if="!error"
77
:src="asset.src"
88
:alt="asset.name"
9-
class="size-full object-contain"
9+
class="size-full object-contain transition-transform duration-300 group-hover:scale-105 group-data-[selected=true]:scale-105"
1010
/>
1111
<div
1212
v-else
1313
class="flex size-full items-center justify-center bg-modal-card-placeholder-background"
1414
>
15-
<i class="pi pi-image text-3xl text-smoke-400" />
15+
<i class="pi pi-image text-3xl text-muted-foreground" />
1616
</div>
1717
</div>
1818
</template>

src/platform/assets/components/MediaVideoTop.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
loop
1414
playsinline
1515
:poster="asset.preview_url"
16-
class="relative size-full object-contain"
16+
class="relative size-full object-contain transition-transform duration-300 group-hover:scale-105 group-data-[selected=true]:scale-105"
1717
@click.stop
1818
@play="onVideoPlay"
1919
@pause="onVideoPause"

0 commit comments

Comments
 (0)