mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-04 20:50:06 +00:00
## 📋 Overview Implemented a new Media Assets sidebar tab in ComfyUI for managing user-uploaded input files and generated output files. This feature supports both local and cloud environments and is currently enabled only in development mode. ## 🎯 Key Features ### 1. Media Assets Sidebar Tab - **Imported** / **Generated** files separated by tabs - Visual display with file preview cards - Gallery view support (navigable with arrow keys) ### 2. Environment-Specific Implementation - **`useInternalMediaAssets`**: For local environment - Fetches file list via `/files` API - Retrieves generation task execution time via `/history` API - Processes history data using the same logic as QueueSidebarTab - **`useCloudMediaAssets`**: For cloud environment - File retrieval through assetService - History data processing using TaskItemImpl - Auto-truncation of long filenames over 20 characters (e.g., `very_long_filename_here.png` → `very_long_...here.png`) ### 3. Execution Time Display - Shows task execution time on generated image cards (e.g., "2.3s") - Calculated from History API's `execution_start` and `execution_success` messages - Displayed at MediaAssetCard's duration chip location ### 4. Gallery Feature - Full-screen gallery mode on image click - Navigate between images with keyboard arrows - Exit gallery with ESC key - Reuses ResultGallery component from QueueSidebarTab ### 5. Development Mode Only - Excluded from production builds using `import.meta.env.DEV` condition - Feature in development, scheduled for official release after stabilization ## 🛠️ Technical Changes ### New Files Added - `src/components/sidebar/tabs/AssetsSidebarTab.vue` - Main sidebar tab component - `src/composables/sidebarTabs/useAssetsSidebarTab.ts` - Sidebar tab definition - `src/composables/useInternalMediaAssets.ts` - Local environment implementation - `src/composables/useCloudMediaAssets.ts` - Cloud environment implementation - `packages/design-system/src/icons/image-ai-edit.svg` - Icon addition ### Modified Files - `src/stores/workspace/sidebarTabStore.ts` - Added dev mode only tab display logic - `src/platform/assets/components/MediaAssetCard.vue` - Added execution time display, zoom event - `src/platform/assets/components/MediaImageTop.vue` - Added image dimension detection - `packages/shared-frontend-utils/src/formatUtil.ts` - Added media type determination utility functions - `src/locales/en/main.json` - Added translation keys [media_asset_OSS_cloud.webm](https://github.com/user-attachments/assets/a6ee3b49-19ed-4735-baad-c2ac2da868ef) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@github.com>
69 lines
1.6 KiB
Vue
69 lines
1.6 KiB
Vue
<template>
|
|
<div
|
|
class="relative size-full overflow-hidden rounded bg-black"
|
|
@mouseenter="isHovered = true"
|
|
@mouseleave="isHovered = false"
|
|
>
|
|
<video
|
|
ref="videoRef"
|
|
:controls="shouldShowControls"
|
|
preload="none"
|
|
:poster="asset.preview_url"
|
|
class="relative size-full object-contain"
|
|
@click.stop
|
|
@play="onVideoPlay"
|
|
@pause="onVideoPause"
|
|
@ended="onVideoEnded"
|
|
>
|
|
<source :src="asset.src || ''" />
|
|
</video>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, onMounted, ref, watch } from 'vue'
|
|
|
|
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
|
|
|
|
const { asset } = defineProps<{
|
|
asset: AssetMeta
|
|
context: AssetContext
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
play: [assetId: string]
|
|
videoPlayingStateChanged: [isPlaying: boolean]
|
|
videoControlsChanged: [showControls: boolean]
|
|
}>()
|
|
|
|
const videoRef = ref<HTMLVideoElement>()
|
|
const isHovered = ref(false)
|
|
const isPlaying = ref(false)
|
|
|
|
// Always show controls when not playing, hide/show based on hover when playing
|
|
const shouldShowControls = computed(() => !isPlaying.value || isHovered.value)
|
|
|
|
watch(shouldShowControls, (controlsVisible) => {
|
|
emit('videoControlsChanged', controlsVisible)
|
|
})
|
|
|
|
onMounted(() => {
|
|
emit('videoControlsChanged', shouldShowControls.value)
|
|
})
|
|
|
|
const onVideoPlay = () => {
|
|
isPlaying.value = true
|
|
emit('videoPlayingStateChanged', true)
|
|
}
|
|
|
|
const onVideoPause = () => {
|
|
isPlaying.value = false
|
|
emit('videoPlayingStateChanged', false)
|
|
}
|
|
|
|
const onVideoEnded = () => {
|
|
isPlaying.value = false
|
|
emit('videoPlayingStateChanged', false)
|
|
}
|
|
</script>
|