Skip to content

Commit 11f8cdb

Browse files
authored
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) ![Before - Touch Device](https://i.imgur.com/V0qcr2D.png) ### After (with fix) - "Generated"/"Imported" tabs visible in header - Action buttons (zoom, menu) visible on left of cards - Duration chips moved to right side ![After - Touch Device](https://i.imgur.com/vQ3dUBc.png) ## 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
1 parent dcf0886 commit 11f8cdb

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

packages/design-system/src/css/style.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
@config '../../tailwind.config.ts';
1111

12+
@custom-variant touch (@media (hover: none));
13+
1214
@theme {
1315
--text-xxs: 0.625rem;
1416
--text-xxs--line-height: calc(1 / 0.625);

src/components/common/TreeExplorerTreeNode.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/>
2929
</div>
3030
<div
31-
class="node-actions motion-safe:opacity-0 motion-safe:group-hover/tree-node:opacity-100"
31+
class="node-actions touch:opacity-100 motion-safe:opacity-0 motion-safe:group-hover/tree-node:opacity-100"
3232
>
3333
<slot name="actions" :node="props.node" />
3434
</div>

src/platform/assets/components/MediaAssetCard.vue

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@
6868
</IconGroup>
6969
</template>
7070

71-
<!-- Output count (top-right) -->
72-
<template v-if="showOutputCount" #top-right>
71+
<!-- Output count or duration chip (top-right) -->
72+
<template v-if="showOutputCount || showTouchDurationChip" #top-right>
7373
<Button
74+
v-if="showOutputCount"
7475
v-tooltip.top.pt:pointer-events-none="
7576
$t('mediaAsset.actions.seeMoreOutputs')
7677
"
@@ -81,6 +82,12 @@
8182
<i class="icon-[lucide--layers] size-4" />
8283
<span>{{ outputCount }}</span>
8384
</Button>
85+
<!-- Duration chip on touch devices (far right) -->
86+
<SquareChip
87+
v-else-if="showTouchDurationChip"
88+
variant="gray"
89+
:label="formattedDuration"
90+
/>
8491
</template>
8592
</CardTop>
8693
</template>
@@ -124,7 +131,7 @@
124131
</template>
125132

126133
<script setup lang="ts">
127-
import { useElementHover, whenever } from '@vueuse/core'
134+
import { useElementHover, useMediaQuery, whenever } from '@vueuse/core'
128135
import { computed, defineAsyncComponent, provide, ref, toRef } from 'vue'
129136
130137
import IconGroup from '@/components/button/IconGroup.vue'
@@ -202,6 +209,7 @@ const showVideoControls = ref(false)
202209
const imageDimensions = ref<{ width: number; height: number } | undefined>()
203210
204211
const isHovered = useElementHover(cardContainerRef)
212+
const isTouch = useMediaQuery('(hover: none)')
205213
206214
const actions = useMediaAssetActions()
207215
@@ -272,19 +280,28 @@ const durationChipClasses = computed(() => {
272280
return ''
273281
})
274282
275-
// Show static chips when NOT hovered and NOT playing (normal state)
283+
// Show static chips when NOT hovered and NOT playing (normal state on non-touch)
276284
const showStaticChips = computed(
277285
() =>
278286
!loading &&
279287
!!asset &&
280288
!isHovered.value &&
281289
!isVideoPlaying.value &&
290+
!isTouch.value &&
282291
formattedDuration.value
283292
)
284293
285-
// Show action overlay when hovered OR playing
294+
// Show duration chip in top-right on touch devices
295+
const showTouchDurationChip = computed(
296+
() => !loading && !!asset && isTouch.value && formattedDuration.value
297+
)
298+
299+
// Show action overlay when hovered, playing, or on touch device
286300
const showActionsOverlay = computed(
287-
() => !loading && !!asset && (isHovered.value || isVideoPlaying.value)
301+
() =>
302+
!loading &&
303+
!!asset &&
304+
(isHovered.value || isVideoPlaying.value || isTouch.value)
288305
)
289306
290307
const handleZoomClick = () => {

0 commit comments

Comments
 (0)