mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 10:59:53 +00:00
fix: make hover-based buttons accessible on touch devices (#7872)
## Summary
- Define `touch:` Tailwind variant using `@media (hover: none)` to
target touch devices
- Add `touch:opacity-100` to `TreeExplorerTreeNode` for node action
buttons
- Add `useMediaQuery('(hover: none)')` to `MediaAssetCard` for action
overlay visibility
## Problem
On touch devices, sidebar buttons that appear on hover are inaccessible
because:
1. The `touch:` Tailwind variant was used but never defined (classes
silently ignored)
2. `TreeExplorerTreeNode` had no touch support for action buttons
3. `MediaAssetCard` used JS-based `useElementHover` which doesn't work
on touch
## Screenshots (Touch Device Emulation)
### Before (main branch)
- No "Generated"/"Imported" tabs visible in header
- Only duration chips shown on cards, no action buttons (zoom, menu)

### After (with fix)
- "Generated"/"Imported" tabs visible in header
- Action buttons (zoom, menu) visible on left of cards
- Duration chips moved to right side

## Test plan
- [ ] On touch device: verify Media Assets sidebar
"Imported"/"Generated" tabs are visible
- [ ] On touch device: verify Node Library filter buttons are visible
- [ ] On touch device: verify tree node action buttons (bookmark, help)
are visible
- [ ] On touch device: verify media asset card zoom/menu buttons are
visible
- [ ] On desktop with mouse: verify hover behavior still works as
expected
This commit is contained in:
committed by
GitHub
parent
dcf0886d89
commit
11f8cdb9bd
@@ -9,6 +9,8 @@
|
||||
|
||||
@config '../../tailwind.config.ts';
|
||||
|
||||
@custom-variant touch (@media (hover: none));
|
||||
|
||||
@theme {
|
||||
--text-xxs: 0.625rem;
|
||||
--text-xxs--line-height: calc(1 / 0.625);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="node-actions motion-safe:opacity-0 motion-safe:group-hover/tree-node:opacity-100"
|
||||
class="node-actions touch:opacity-100 motion-safe:opacity-0 motion-safe:group-hover/tree-node:opacity-100"
|
||||
>
|
||||
<slot name="actions" :node="props.node" />
|
||||
</div>
|
||||
|
||||
@@ -68,9 +68,10 @@
|
||||
</IconGroup>
|
||||
</template>
|
||||
|
||||
<!-- Output count (top-right) -->
|
||||
<template v-if="showOutputCount" #top-right>
|
||||
<!-- Output count or duration chip (top-right) -->
|
||||
<template v-if="showOutputCount || showTouchDurationChip" #top-right>
|
||||
<Button
|
||||
v-if="showOutputCount"
|
||||
v-tooltip.top.pt:pointer-events-none="
|
||||
$t('mediaAsset.actions.seeMoreOutputs')
|
||||
"
|
||||
@@ -81,6 +82,12 @@
|
||||
<i class="icon-[lucide--layers] size-4" />
|
||||
<span>{{ outputCount }}</span>
|
||||
</Button>
|
||||
<!-- Duration chip on touch devices (far right) -->
|
||||
<SquareChip
|
||||
v-else-if="showTouchDurationChip"
|
||||
variant="gray"
|
||||
:label="formattedDuration"
|
||||
/>
|
||||
</template>
|
||||
</CardTop>
|
||||
</template>
|
||||
@@ -124,7 +131,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useElementHover, whenever } from '@vueuse/core'
|
||||
import { useElementHover, useMediaQuery, whenever } from '@vueuse/core'
|
||||
import { computed, defineAsyncComponent, provide, ref, toRef } from 'vue'
|
||||
|
||||
import IconGroup from '@/components/button/IconGroup.vue'
|
||||
@@ -202,6 +209,7 @@ const showVideoControls = ref(false)
|
||||
const imageDimensions = ref<{ width: number; height: number } | undefined>()
|
||||
|
||||
const isHovered = useElementHover(cardContainerRef)
|
||||
const isTouch = useMediaQuery('(hover: none)')
|
||||
|
||||
const actions = useMediaAssetActions()
|
||||
|
||||
@@ -272,19 +280,28 @@ const durationChipClasses = computed(() => {
|
||||
return ''
|
||||
})
|
||||
|
||||
// Show static chips when NOT hovered and NOT playing (normal state)
|
||||
// Show static chips when NOT hovered and NOT playing (normal state on non-touch)
|
||||
const showStaticChips = computed(
|
||||
() =>
|
||||
!loading &&
|
||||
!!asset &&
|
||||
!isHovered.value &&
|
||||
!isVideoPlaying.value &&
|
||||
!isTouch.value &&
|
||||
formattedDuration.value
|
||||
)
|
||||
|
||||
// Show action overlay when hovered OR playing
|
||||
// Show duration chip in top-right on touch devices
|
||||
const showTouchDurationChip = computed(
|
||||
() => !loading && !!asset && isTouch.value && formattedDuration.value
|
||||
)
|
||||
|
||||
// Show action overlay when hovered, playing, or on touch device
|
||||
const showActionsOverlay = computed(
|
||||
() => !loading && !!asset && (isHovered.value || isVideoPlaying.value)
|
||||
() =>
|
||||
!loading &&
|
||||
!!asset &&
|
||||
(isHovered.value || isVideoPlaying.value || isTouch.value)
|
||||
)
|
||||
|
||||
const handleZoomClick = () => {
|
||||
|
||||
Reference in New Issue
Block a user