Skip to content

Commit bf5752d

Browse files
authored
Merge pull request #246 from liweicheng00/feat/preview-images
(feat) add media preview modal
2 parents 78cc843 + f142af2 commit bf5752d

File tree

10 files changed

+174
-6
lines changed

10 files changed

+174
-6
lines changed

src/components/SvgIcon/SvgIcon.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
fill: var(--chat-icon-color-close-outline);
3535
}
3636

37+
#vac-icon-close-outline-preview {
38+
fill: var(--chat-icon-color-close-preview);
39+
}
40+
3741
#vac-icon-send {
3842
fill: var(--chat-icon-color-send);
3943
}

src/lib/ChatWindow.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
background: var(--chat-content-bg-color);
66
color: var(--chat-color);
77
overflow-wrap: break-word;
8-
position: relative;
98
white-space: normal;
109
border: var(--chat-container-border);
1110
border-radius: var(--chat-container-border-radius);

src/lib/ChatWindow.vue

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,20 @@
8181
</template>
8282
</room>
8383
</div>
84+
<transition name="vac-fade-preview" appear>
85+
<media-preview
86+
v-if="showMediaPreview"
87+
:file="previewFile"
88+
@close-media-preview="showMediaPreview = false"
89+
/>
90+
</transition>
8491
</div>
8592
</template>
8693

8794
<script>
8895
import RoomsList from './RoomsList/RoomsList'
8996
import Room from './Room/Room'
97+
import MediaPreview from './MediaPreview/MediaPreview'
9098
9199
import locales from '../locales'
92100
import { defaultThemeStyles, cssThemeVars } from '../themes'
@@ -99,7 +107,8 @@ export default {
99107
name: 'ChatContainer',
100108
components: {
101109
RoomsList,
102-
Room
110+
Room,
111+
MediaPreview
103112
},
104113
105114
props: {
@@ -163,7 +172,8 @@ export default {
163172
roomMessage: { type: String, default: '' },
164173
scrollDistance: { type: Number, default: 60 },
165174
acceptedFiles: { type: String, default: '*' },
166-
templatesText: { type: Array, default: null }
175+
templatesText: { type: Array, default: null },
176+
mediaPreviewEnabled: { type: Boolean, default: true }
167177
},
168178
169179
emits: [
@@ -191,7 +201,9 @@ export default {
191201
room: {},
192202
loadingMoreRooms: false,
193203
showRoomsList: true,
194-
isMobile: false
204+
isMobile: false,
205+
showMediaPreview: false,
206+
previewFile: {}
195207
}
196208
},
197209
@@ -333,7 +345,12 @@ export default {
333345
this.$emit('delete-message', { message, roomId: this.room.roomId })
334346
},
335347
openFile({ message, file }) {
336-
this.$emit('open-file', { message, file })
348+
if (this.mediaPreviewEnabled && file.action === 'preview') {
349+
this.previewFile = file.file
350+
this.showMediaPreview = true
351+
} else {
352+
this.$emit('open-file', { message, file })
353+
}
337354
},
338355
openUserTag({ user }) {
339356
this.$emit('open-user-tag', { user })
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.vac-media-preview {
2+
position: absolute;
3+
top: 0;
4+
left: 0;
5+
z-index: 99;
6+
width: 100vw;
7+
height: 100vh;
8+
background-color: rgba(0, 0, 0, 0.8);
9+
outline: none;
10+
11+
.vac-media-preview-container {
12+
width: 100%;
13+
height: 100%;
14+
}
15+
16+
.vac-image-preview {
17+
width: 100%;
18+
height: 100%;
19+
background-size: contain;
20+
background-repeat: no-repeat;
21+
background-position: center;
22+
}
23+
24+
.vac-svg-button {
25+
position: absolute;
26+
top: 30px;
27+
right: 30px;
28+
transform: scale(1.4);
29+
}
30+
31+
@media only screen and (max-width: 768px) {
32+
.vac-svg-button {
33+
top: 20px;
34+
right: 20px;
35+
transform: scale(1.2);
36+
}
37+
}
38+
}

src/lib/MediaPreview/MediaPreview.vue

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<template>
2+
<div
3+
ref="modal"
4+
tabindex="0"
5+
class="vac-media-preview"
6+
@click.stop="closeModal"
7+
@keydown.esc="closeModal"
8+
>
9+
<transition name="vac-bounce-preview" appear>
10+
<div v-if="isImage" class="vac-media-preview-container">
11+
<div
12+
class="vac-image-preview"
13+
:style="{
14+
'background-image': `url('${file.url}')`
15+
}"
16+
/>
17+
</div>
18+
19+
<div v-else-if="isVideo" class="vac-media-preview-container">
20+
<video width="100%" height="100%" controls autoplay>
21+
<source :src="file.url" />
22+
</video>
23+
</div>
24+
</transition>
25+
26+
<div class="vac-svg-button">
27+
<slot name="preview-close-icon">
28+
<svg-icon name="close-outline" param="preview" />
29+
</slot>
30+
</div>
31+
</div>
32+
</template>
33+
<script>
34+
import SvgIcon from '../../components/SvgIcon/SvgIcon'
35+
36+
const { isImageFile, isVideoFile } = require('../../utils/media-file')
37+
38+
export default {
39+
name: 'MediaPreview',
40+
components: {
41+
SvgIcon
42+
},
43+
44+
props: {
45+
file: { type: Object, required: true }
46+
},
47+
48+
emits: ['close-media-preview'],
49+
50+
computed: {
51+
isImage() {
52+
return isImageFile(this.file)
53+
},
54+
isVideo() {
55+
return isVideoFile(this.file)
56+
}
57+
},
58+
59+
mounted() {
60+
this.$refs.modal.focus()
61+
},
62+
63+
methods: {
64+
closeModal() {
65+
this.$emit('close-media-preview')
66+
}
67+
}
68+
}
69+
</script>

src/lib/Message/MessageFiles/MessageFile/MessageFile.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
width: 350px;
5656
max-width: 100%;
5757
margin: 4px auto 5px;
58+
cursor: pointer;
5859

5960
video {
6061
border-radius: 4px;

src/lib/Message/MessageFiles/MessageFile/MessageFile.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@
5858
</div>
5959
</div>
6060

61-
<div v-else-if="isVideo" class="vac-video-container">
61+
<div
62+
v-else-if="isVideo"
63+
class="vac-video-container"
64+
@click.stop.prevent="openFile('preview')"
65+
>
6266
<video width="100%" height="100%" controls>
6367
<source :src="file.url" />
6468
</video>

src/styles/animation.scss

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,34 @@
9898
transform: scale(1);
9999
}
100100
}
101+
102+
// Open media preview animation
103+
.vac-fade-preview-enter {
104+
opacity: 0;
105+
}
106+
107+
.vac-fade-preview-enter-active {
108+
transition: opacity 0.1s;
109+
}
110+
111+
.vac-fade-preview-leave-active {
112+
transition: opacity 0.2s;
113+
opacity: 0;
114+
}
115+
116+
.vac-bounce-preview-enter-active {
117+
animation: vac-bounce-image-in 0.4s;
118+
}
119+
120+
.vac-bounce-preview-leave-active {
121+
animation: vac-bounce-image-in 0.3s reverse;
122+
}
123+
124+
@keyframes vac-bounce-image-in {
125+
0% {
126+
transform: scale(0.6);
127+
}
128+
100% {
129+
transform: scale(1);
130+
}
131+
}

src/styles/index.scss

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

55
@import '../lib/ChatWindow';
66

7+
@import '../lib/MediaPreview/MediaPreview';
8+
79
@import '../lib/Room/Room';
810
@import '../lib/Room/RoomEmojis/RoomEmojis';
911
@import '../lib/Room/RoomHeader/RoomHeader';

src/themes/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export const defaultThemeStyles = {
119119
file: '#1976d2',
120120
paperclip: '#1976d2',
121121
closeOutline: '#000',
122+
closePreview: '#fff',
122123
send: '#1976d2',
123124
sendDisabled: '#9ca6af',
124125
emoji: '#1976d2',
@@ -259,6 +260,7 @@ export const defaultThemeStyles = {
259260
file: '#1976d2',
260261
paperclip: '#fff',
261262
closeOutline: '#fff',
263+
closePreview: '#fff',
262264
send: '#fff',
263265
sendDisabled: '#646a70',
264266
emoji: '#fff',
@@ -407,6 +409,7 @@ export const cssThemeVars = ({
407409
'--chat-icon-color-file': icons.file,
408410
'--chat-icon-color-paperclip': icons.paperclip,
409411
'--chat-icon-color-close-outline': icons.closeOutline,
412+
'--chat-icon-color-close-preview': icons.closePreview,
410413
'--chat-icon-color-send': icons.send,
411414
'--chat-icon-color-send-disabled': icons.sendDisabled,
412415
'--chat-icon-color-emoji': icons.emoji,

0 commit comments

Comments
 (0)