feat: Improve MediaAssetCard video controls and add gallery view (#6065)

## Summary
- Enhanced video control visibility logic for better UX
- Added fullscreen gallery view with zoom-in button  
- Fixed hover interaction issues with overlays

## Changes

### Video Controls
- **Before**: Controls hidden when not hovering
- **After**: Controls always visible when not playing, hover-based
during playback

### Overlay Behavior  
- **Before**: All overlays hidden during video playback
- **After**: All overlays (actions, tags, layers) show on hover even
during playback

### Gallery View
- Added zoom-in button to top-right corner (all media types except 3D)
- Integrated with existing ResultGallery component
- Gallery closes when clicking dimmed background area

### Bug Fixes
- Fixed hover flicker issue by proper event handling on overlay elements

## Test Plan
- [x] Test video controls visibility (paused vs playing)
- [x] Test overlay hover behavior during video playback
- [x] Test zoom-in button opens gallery view
- [x] Test gallery closes on background click
- [x] Test 3D assets don't show zoom button
- [x] Test in Storybook with various media types

🤖 Generated with [Claude Code](https://claude.ai/code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6065-feat-Improve-MediaAssetCard-video-controls-and-add-gallery-view-28d6d73d3650818c90cfc5d0d00e4826)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Jin Yi
2025-10-16 03:45:55 +09:00
committed by GitHub
parent 97417736be
commit 4dab27a84e
7 changed files with 348 additions and 49 deletions

View File

@@ -1,18 +1,19 @@
<template>
<div
class="relative h-full w-full overflow-hidden rounded bg-black"
@mouseenter="showControls = true"
@mouseleave="showControls = false"
@mouseenter="isHovered = true"
@mouseleave="isHovered = false"
>
<video
ref="videoRef"
:controls="showControls"
:controls="shouldShowControls"
preload="none"
:poster="asset.preview_url"
class="relative h-full w-full object-contain"
@click.stop
@play="onVideoPlay"
@pause="onVideoPause"
@ended="onVideoEnded"
>
<source :src="asset.src || ''" />
</video>
@@ -20,7 +21,7 @@
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
@@ -36,22 +37,32 @@ const emit = defineEmits<{
}>()
const videoRef = ref<HTMLVideoElement>()
const showControls = ref(true)
const isHovered = ref(false)
const isPlaying = ref(false)
watch(showControls, (controlsVisible) => {
// 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', showControls.value)
emit('videoControlsChanged', shouldShowControls.value)
})
const onVideoPlay = () => {
showControls.value = true
isPlaying.value = true
emit('videoPlayingStateChanged', true)
}
const onVideoPause = () => {
isPlaying.value = false
emit('videoPlayingStateChanged', false)
}
const onVideoEnded = () => {
isPlaying.value = false
emit('videoPlayingStateChanged', false)
}
</script>