Skip to content

Commit 178c79e

Browse files
[fix] Make gallery navigation buttons visible on mobile devices (#3953)
1 parent 7c0040b commit 178c79e

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { mount } from '@vue/test-utils'
2+
import PrimeVue from 'primevue/config'
3+
import Galleria from 'primevue/galleria'
4+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5+
import { createApp, nextTick } from 'vue'
6+
7+
import type { NodeId } from '@/schemas/comfyWorkflowSchema'
8+
import type { ResultItemImpl } from '@/stores/queueStore'
9+
10+
import ResultGallery from './ResultGallery.vue'
11+
12+
type MockResultItem = Partial<ResultItemImpl> & {
13+
filename: string
14+
subfolder: string
15+
type: string
16+
nodeId: NodeId
17+
mediaType: string
18+
id?: string
19+
url?: string
20+
isImage?: boolean
21+
isVideo?: boolean
22+
}
23+
24+
describe('ResultGallery', () => {
25+
// Mock ComfyImage and ResultVideo components
26+
const mockComfyImage = {
27+
name: 'ComfyImage',
28+
template: '<div class="mock-comfy-image" data-testid="comfy-image"></div>',
29+
props: ['src', 'contain', 'alt']
30+
}
31+
32+
const mockResultVideo = {
33+
name: 'ResultVideo',
34+
template:
35+
'<div class="mock-result-video" data-testid="result-video"></div>',
36+
props: ['result']
37+
}
38+
39+
// Sample gallery items - using mock instances with only required properties
40+
const mockGalleryItems: MockResultItem[] = [
41+
{
42+
filename: 'image1.jpg',
43+
subfolder: 'outputs',
44+
type: 'output',
45+
nodeId: '123' as NodeId,
46+
mediaType: 'images',
47+
isImage: true,
48+
isVideo: false,
49+
url: 'image1.jpg',
50+
id: '1'
51+
},
52+
{
53+
filename: 'image2.jpg',
54+
subfolder: 'outputs',
55+
type: 'output',
56+
nodeId: '456' as NodeId,
57+
mediaType: 'images',
58+
isImage: true,
59+
isVideo: false,
60+
url: 'image2.jpg',
61+
id: '2'
62+
}
63+
]
64+
65+
beforeEach(() => {
66+
const app = createApp({})
67+
app.use(PrimeVue)
68+
69+
// Create mock elements for Galleria to find
70+
document.body.innerHTML = `
71+
<div id="app"></div>
72+
`
73+
})
74+
75+
afterEach(() => {
76+
// Clean up any elements added to body
77+
document.body.innerHTML = ''
78+
vi.restoreAllMocks()
79+
})
80+
81+
const mountGallery = (props = {}) => {
82+
return mount(ResultGallery, {
83+
global: {
84+
plugins: [PrimeVue],
85+
components: {
86+
Galleria,
87+
ComfyImage: mockComfyImage,
88+
ResultVideo: mockResultVideo
89+
},
90+
stubs: {
91+
teleport: true
92+
}
93+
},
94+
props: {
95+
allGalleryItems: mockGalleryItems as unknown as ResultItemImpl[],
96+
activeIndex: 0,
97+
...props
98+
},
99+
attachTo: document.getElementById('app') || undefined
100+
})
101+
}
102+
103+
it('renders Galleria component with correct props', async () => {
104+
const wrapper = mountGallery()
105+
106+
await nextTick() // Wait for component to mount
107+
108+
const galleria = wrapper.findComponent(Galleria)
109+
expect(galleria.exists()).toBe(true)
110+
expect(galleria.props('value')).toEqual(mockGalleryItems)
111+
expect(galleria.props('showIndicators')).toBe(false)
112+
expect(galleria.props('showItemNavigators')).toBe(true)
113+
expect(galleria.props('fullScreen')).toBe(true)
114+
})
115+
116+
it('shows gallery when activeIndex changes from -1', async () => {
117+
const wrapper = mountGallery({ activeIndex: -1 })
118+
119+
// Initially galleryVisible should be false
120+
const vm: any = wrapper.vm
121+
expect(vm.galleryVisible).toBe(false)
122+
123+
// Change activeIndex
124+
await wrapper.setProps({ activeIndex: 0 })
125+
await nextTick()
126+
127+
// galleryVisible should become true
128+
expect(vm.galleryVisible).toBe(true)
129+
})
130+
131+
it('should render the component properly', () => {
132+
// This is a meta-test to confirm the component mounts properly
133+
const wrapper = mountGallery()
134+
135+
// We can't directly test the compiled CSS, but we can verify the component renders
136+
expect(wrapper.exists()).toBe(true)
137+
138+
// Verify that the Galleria component exists and is properly mounted
139+
const galleria = wrapper.findComponent(Galleria)
140+
expect(galleria.exists()).toBe(true)
141+
})
142+
143+
it('ensures correct configuration for mobile viewport', async () => {
144+
// Mock window.matchMedia to simulate mobile viewport
145+
Object.defineProperty(window, 'matchMedia', {
146+
writable: true,
147+
value: vi.fn().mockImplementation((query) => ({
148+
matches: query.includes('max-width: 768px'),
149+
media: query,
150+
onchange: null,
151+
addListener: vi.fn(),
152+
removeListener: vi.fn(),
153+
addEventListener: vi.fn(),
154+
removeEventListener: vi.fn(),
155+
dispatchEvent: vi.fn()
156+
}))
157+
})
158+
159+
const wrapper = mountGallery()
160+
await nextTick()
161+
162+
// Verify mobile media query is working
163+
expect(window.matchMedia('(max-width: 768px)').matches).toBe(true)
164+
165+
// Check if the component renders with Galleria
166+
const galleria = wrapper.findComponent(Galleria)
167+
expect(galleria.exists()).toBe(true)
168+
169+
// Check that our PT props for positioning work correctly
170+
const pt = galleria.props('pt') as any
171+
expect(pt?.prevButton?.style).toContain('position: fixed')
172+
expect(pt?.nextButton?.style).toContain('position: fixed')
173+
})
174+
175+
// Additional tests for interaction could be added once we can reliably
176+
// test Galleria component in fullscreen mode
177+
})

src/components/sidebar/tabs/queue/ResultGallery.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,12 @@ img.galleria-image {
144144
/* Set z-index so the close button doesn't get hidden behind the image when image is large */
145145
z-index: 1;
146146
}
147+
148+
/* Mobile/tablet specific fixes */
149+
@media screen and (max-width: 768px) {
150+
.p-galleria-prev-button,
151+
.p-galleria-next-button {
152+
z-index: 2;
153+
}
154+
}
147155
</style>

0 commit comments

Comments
 (0)