Skip to content

Commit 04b67e9

Browse files
committed
feat: [Request] Carousel with thumbnails view (closes quasarframework#1786)
1 parent c59b3cd commit 04b67e9

File tree

10 files changed

+200
-12
lines changed

10 files changed

+200
-12
lines changed

dev/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
hide-underline
3838
stack-label="Icon set"
3939
:options="[
40-
{ label: 'Material', value: 'material' }
40+
{ label: 'Material', value: 'material-icons' }
4141
,{ label: 'MDI', value: 'mdi' }
4242
,{ label: 'Ionicons', value: 'ionicons' }
4343
,{ label: 'Fontawesome', value: 'fontawesome' }

dev/components/components/carousel.vue

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,37 @@
2828
<q-carousel-slide img-src="statics/parallax2.jpg" />
2929
</q-carousel>
3030

31+
<p class="caption">Thumbnails</p>
32+
<q-carousel
33+
color="white"
34+
arrows
35+
quick-nav
36+
height="300px"
37+
:thumbnails="[
38+
'statics/mountains.jpg',
39+
'statics/parallax1.jpg',
40+
'statics/parallax2.jpg',
41+
42+
'statics/mountains.jpg',
43+
'statics/parallax1.jpg',
44+
'statics/parallax2.jpg',
45+
'statics/mountains.jpg',
46+
'statics/parallax1.jpg',
47+
'statics/parallax2.jpg',
48+
]"
49+
>
50+
<q-carousel-slide img-src="statics/mountains.jpg" />
51+
<q-carousel-slide img-src="statics/parallax1.jpg" />
52+
<q-carousel-slide img-src="statics/parallax2.jpg" />
53+
54+
<q-carousel-slide img-src="statics/mountains.jpg" />
55+
<q-carousel-slide img-src="statics/parallax1.jpg" />
56+
<q-carousel-slide img-src="statics/parallax2.jpg" />
57+
<q-carousel-slide img-src="statics/mountains.jpg" />
58+
<q-carousel-slide img-src="statics/parallax1.jpg" />
59+
<q-carousel-slide img-src="statics/parallax2.jpg" />
60+
</q-carousel>
61+
3162
<p class="caption">Example creating custom captions for each slide.</p>
3263
<q-carousel
3364
color="white"

icons/fontawesome-pro.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export default {
2929
carousel: {
3030
left: 'fal fa-chevron-left',
3131
right: 'fal fa-chevron-right', // TODO
32-
quickNav: 'fal fa-circle'
32+
quickNav: 'fal fa-circle',
33+
thumbnails: 'fal fa-th'
3334
},
3435
checkbox: { // TODO
3536
checked: {

icons/fontawesome.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export default {
2929
carousel: {
3030
left: 'fas fa-chevron-left',
3131
right: 'fas fa-chevron-right', // TODO
32-
quickNav: 'fas fa-circle'
32+
quickNav: 'fas fa-circle',
33+
thumbnails: 'fas fa-th'
3334
},
3435
checkbox: { // TODO
3536
checked: {

icons/ionicons.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export default {
2929
carousel: {
3030
left: 'ion-chevron-left',
3131
right: 'ion-chevron-right',
32-
quickNav: 'ion-record'
32+
quickNav: 'ion-record',
33+
thumbnails: 'ion-grid'
3334
},
3435
checkbox: {
3536
checked: {

icons/material-icons.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export default {
2-
name: 'material',
2+
name: 'material-icons',
33
type: {
44
positive: 'check_circle',
55
negative: 'warning',
@@ -29,7 +29,8 @@ export default {
2929
carousel: {
3030
left: 'chevron_left',
3131
right: 'chevron_right',
32-
quickNav: 'lens'
32+
quickNav: 'lens',
33+
thumbnails: 'view_carousel'
3334
},
3435
checkbox: {
3536
checked: {

icons/mdi.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export default {
2929
carousel: {
3030
left: 'mdi-chevron-left',
3131
right: 'mdi-chevron-right',
32-
quickNav: 'mdi-circle'
32+
quickNav: 'mdi-circle',
33+
thumbnails: 'mdi-view-carousel'
3334
},
3435
checkbox: {
3536
checked: {

src/components/carousel/QCarousel.js

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ export default {
3838
default: 'bottom',
3939
validator: v => ['top', 'bottom'].includes(v)
4040
},
41-
quickNavIcon: String
41+
quickNavIcon: String,
42+
thumbnails: {
43+
type: Array,
44+
default: () => ([])
45+
},
46+
thumbnailsIcon: String
4247
},
4348
provide () {
4449
return {
@@ -51,7 +56,8 @@ export default {
5156
slide: 0,
5257
positionSlide: 0,
5358
slidesNumber: 0,
54-
animUid: false
59+
animUid: false,
60+
viewThumbnails: false
5561
}
5662
},
5763
watch: {
@@ -119,6 +125,9 @@ export default {
119125
canGoToNext: this.canGoToNext,
120126
canGoToPrevious: this.canGoToPrevious
121127
}
128+
},
129+
computedThumbnailIcon () {
130+
return this.thumbnailIcon || this.$q.icon.carousel.thumbnails
122131
}
123132
},
124133
methods: {
@@ -335,9 +344,7 @@ export default {
335344
color: this.color
336345
},
337346
on: {
338-
click: () => {
339-
this.goToSlide(i)
340-
}
347+
click: () => { this.goToSlide(i) }
341348
}
342349
}))
343350
}
@@ -347,6 +354,58 @@ export default {
347354
staticClass: 'q-carousel-quick-nav scroll text-center',
348355
'class': [`text-${this.color}`, `absolute-${this.quickNavPosition}`]
349356
}, items)
357+
},
358+
__getThumbnails (h) {
359+
const slides = this.thumbnails.map((img, index) => {
360+
if (!img) {
361+
return
362+
}
363+
364+
return h('div', {
365+
on: {
366+
click: () => { this.goToSlide(index) }
367+
}
368+
}, [
369+
h('img', {
370+
attrs: { src: img },
371+
'class': { active: this.slide === index }
372+
})
373+
])
374+
})
375+
376+
const nodes = [
377+
h(QBtn, {
378+
staticClass: 'q-carousel-thumbnail-btn absolute',
379+
props: {
380+
icon: this.computedThumbnailIcon,
381+
fabMini: true,
382+
flat: true,
383+
color: this.color
384+
},
385+
on: {
386+
click: () => {
387+
this.viewThumbnails = !this.viewThumbnails
388+
}
389+
}
390+
}),
391+
h('div', {
392+
staticClass: 'q-carousel-thumbnails scroll text-center absolute-bottom',
393+
'class': { active: this.viewThumbnails }
394+
}, slides)
395+
]
396+
397+
if (this.viewThumbnails) {
398+
nodes.unshift(
399+
h('div', {
400+
staticClass: 'absolute-full',
401+
on: {
402+
click: () => { this.viewThumbnails = false }
403+
}
404+
})
405+
)
406+
}
407+
408+
return nodes
350409
}
351410
},
352411
render (h) {
@@ -397,6 +456,9 @@ export default {
397456
}) : null,
398457
this.__getQuickNav(h),
399458
this.__getScopedSlots(h),
459+
this.thumbnails.length
460+
? this.__getThumbnails(h)
461+
: null,
400462
this.$slots.control
401463
])
402464
},

src/components/carousel/carousel.ios.styl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,48 @@
4545
opacity .5
4646
.q-icon
4747
font-size $carousel-quick-nav-icon-inactive-font-size !important
48+
49+
.q-carousel-thumbnails
50+
will-change transform
51+
transition transform .3s
52+
transform translateY(105%)
53+
width 100%
54+
height auto
55+
max-height 60%
56+
overflow auto
57+
background black
58+
padding-top .5rem
59+
padding-bottom 2.2rem
60+
text-align center
61+
box-shadow 0 -3px 6px rgba(0, 0, 0, .16), 0 -5px 6px rgba(0, 0, 0, .23)
62+
63+
&.active
64+
transform translateY(0)
65+
66+
img
67+
height auto
68+
width 100%
69+
display block
70+
opacity .5
71+
will-change opacity
72+
transition opacity .3s
73+
cursor pointer
74+
border 1px solid black
75+
76+
div
77+
margin 1px 2px
78+
width 100px
79+
min-width 100px
80+
display inline-block
81+
82+
&.active img, img.active
83+
opacity 1
84+
border-color white
85+
86+
.q-carousel-thumbnail-btn
87+
background $carousel-quick-nav-background
88+
top 5px
89+
right 5px
90+
91+
body.desktop .q-carousel-thumbnails img:hover
92+
opacity 1

src/components/carousel/carousel.mat.styl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,48 @@
4545
opacity .5
4646
.q-icon
4747
font-size $carousel-quick-nav-icon-inactive-font-size !important
48+
49+
.q-carousel-thumbnails
50+
will-change transform
51+
transition transform .3s
52+
transform translateY(105%)
53+
width 100%
54+
height auto
55+
max-height 60%
56+
overflow auto
57+
background black
58+
padding-top .5rem
59+
padding-bottom 2.2rem
60+
text-align center
61+
box-shadow 0 -3px 6px rgba(0, 0, 0, .16), 0 -5px 6px rgba(0, 0, 0, .23)
62+
63+
&.active
64+
transform translateY(0)
65+
66+
img
67+
height auto
68+
width 100%
69+
display block
70+
opacity .5
71+
will-change opacity
72+
transition opacity .3s
73+
cursor pointer
74+
border 1px solid black
75+
76+
div
77+
margin 1px 2px
78+
width 100px
79+
min-width 100px
80+
display inline-block
81+
82+
&.active img, img.active
83+
opacity 1
84+
border-color white
85+
86+
.q-carousel-thumbnail-btn
87+
background $carousel-quick-nav-background
88+
top 5px
89+
right 5px
90+
91+
body.desktop .q-carousel-thumbnails img:hover
92+
opacity 1

0 commit comments

Comments
 (0)