add emojiPicker and microphone
This commit is contained in:
parent
d3031a1e70
commit
fb707fcde3
@ -34,6 +34,7 @@
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^7.5.0",
|
||||
"node-sass": "^5.0.0",
|
||||
"recorder-js": "*",
|
||||
"sass-loader": "^10.1.1",
|
||||
"vue-router": "^3.4.9",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
|
1
public/sym/ic_insert_emoticon_white.svg
Normal file
1
public/sym/ic_insert_emoticon_white.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></svg>
|
After Width: | Height: | Size: 510 B |
1
public/sym/ic_mic_white.svg
Normal file
1
public/sym/ic_mic_white.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/></svg>
|
After Width: | Height: | Size: 348 B |
@ -1,22 +1,57 @@
|
||||
<template>
|
||||
<div class="newMessageBanner" ref="newMessageBanner">
|
||||
<reply-event v-if="replyTo" :event="replyTo" @click.native="resetReplyTo()"/>
|
||||
<form v-on:submit.prevent="sendMessage()">
|
||||
<textarea
|
||||
@keyup.enter.exact="sendMessage()"
|
||||
@input="resizeMessageBanner(); sendTyping(2000);"
|
||||
v-model="event.content.body"
|
||||
ref="newMessageInput" class="newMessageInput"
|
||||
rows="1" placeholder="type a message ..."
|
||||
/>
|
||||
<div class="newMessageBanner" ref="newMessageBanner">
|
||||
<reply-event v-if="replyTo" :event="replyTo" @click.native="resetReplyTo()"/>
|
||||
<form v-on:submit.prevent="sendMessage()">
|
||||
<textarea
|
||||
@keyup.enter.exact="sendMessage()"
|
||||
@input="resizeMessageBanner(); sendTyping(2000);"
|
||||
v-model="event.content.body"
|
||||
ref="newMessageInput" class="newMessageInput"
|
||||
rows="1" placeholder="type a message ..."
|
||||
/>
|
||||
<icon
|
||||
v-if="event.content.body && !isRecording"
|
||||
type="submit"
|
||||
title="press enter to submit"
|
||||
class="sendMessageBtn"
|
||||
ic="./sym/ic_send_white.svg"
|
||||
/>
|
||||
<div v-else class="recorder">
|
||||
<icon
|
||||
v-if="!isRecording"
|
||||
title="record voice"
|
||||
class="recordBtn start"
|
||||
ic="./sym/ic_mic_white.svg"
|
||||
@click.native="startRecording()"
|
||||
ref="startRecord"
|
||||
/>
|
||||
<div v-else class="voiceMeterContainer">
|
||||
<div class="voiceMeter" ref="voiceMeter"></div>
|
||||
<icon
|
||||
title="record voice"
|
||||
class="recordBtn stop"
|
||||
ic="./sym/ic_mic_white.svg"
|
||||
@click.native="stopRecording()"
|
||||
ref="stopRecord"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<icon
|
||||
type="submit"
|
||||
title="press enter to submit"
|
||||
class="sendMessageBtn"
|
||||
ic="./sym/ic_send_white.svg"
|
||||
title="toggle emoji"
|
||||
class="emojiToggle"
|
||||
ic="./sym/ic_insert_emoticon_white.svg"
|
||||
@click.native="toggleEmojiPicker()"
|
||||
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
<v-emoji-picker
|
||||
v-if="showEmojiPicker"
|
||||
class="emojiPicker"
|
||||
@select="onSelectEmoji"
|
||||
:dark="true"
|
||||
:continuousList="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -25,12 +60,16 @@ import {matrix} from '@/main.js';
|
||||
import {parseMessage} from '@/lib/eventUtils';
|
||||
import {calcUserName} from '@/lib/matrixUtils';
|
||||
import ReplyEvent from '@/components/replyEvent';
|
||||
import {VEmojiPicker} from 'v-emoji-picker';
|
||||
import Recorder from 'recorder-js';
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
|
||||
export default {
|
||||
name: 'newMessage',
|
||||
components: {
|
||||
ReplyEvent,
|
||||
icon
|
||||
icon,
|
||||
VEmojiPicker
|
||||
},
|
||||
props: {
|
||||
onResize: Function,
|
||||
@ -69,6 +108,26 @@ export default {
|
||||
onSelectEmoji(emoji) {
|
||||
this.event.content.body += emoji.data;
|
||||
},
|
||||
startRecording(){
|
||||
navigator.mediaDevices.getUserMedia({audio: true})
|
||||
.then(stream => {
|
||||
this.recorder.init(stream);
|
||||
this.recorder.start().then(()=>this.isRecording=true);
|
||||
})
|
||||
.catch(err => console.log('unable to get stream', err));
|
||||
},
|
||||
stopRecording(){
|
||||
this.recorder.stop()
|
||||
.then(({blob}) => {
|
||||
this.recBlob = blob;
|
||||
this.isRecording=false;
|
||||
});
|
||||
},
|
||||
setVoiceMeter(value){
|
||||
if (!this.$refs.stopRecord) return;
|
||||
this.$refs.voiceMeter.style.height = `calc(3rem + ${value/4}px`;
|
||||
this.$refs.voiceMeter.style.width = `calc(3rem + ${value/4}px`;
|
||||
},
|
||||
parseMessage,
|
||||
calcUserName
|
||||
},
|
||||
@ -87,7 +146,12 @@ export default {
|
||||
}
|
||||
},
|
||||
showEmojiPicker: false,
|
||||
waitForSendTyping: false
|
||||
waitForSendTyping: false,
|
||||
recorder: new Recorder(audioContext, {
|
||||
onAnalysed: data => this.setVoiceMeter(data.lineTo)
|
||||
}),
|
||||
isRecording: false,
|
||||
recBlob: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,7 +173,7 @@ export default {
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0;
|
||||
left: 1rem;
|
||||
left: 3rem;
|
||||
min-height: 1.5rem;
|
||||
max-height: 10rem;
|
||||
width: calc(100% - 7rem);
|
||||
@ -144,4 +208,58 @@ export default {
|
||||
.username{
|
||||
font-weight: bold;
|
||||
}
|
||||
.emojiPicker{
|
||||
position: absolute;
|
||||
bottom: calc(100% + 0.25rem);
|
||||
left: 0.25rem;
|
||||
z-index: 10;
|
||||
max-width: calc(100% - 0.5rem - 2px);
|
||||
}
|
||||
.emojiToggle{
|
||||
position: absolute;
|
||||
left: 0.25rem;
|
||||
bottom: 0.5rem;
|
||||
background-color: unset;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
.recordBtn{
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 0.25rem;
|
||||
background-color: #1d1d1d;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.recordBtn.stop{
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #c63e3e;
|
||||
box-shadow: none;
|
||||
}
|
||||
.voiceMeter{
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
border-radius: 50%;
|
||||
box-shadow: 3px 3px 10px #111;
|
||||
}
|
||||
.voiceMeterContainer{
|
||||
position: absolute;
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
bottom: 0.25rem;
|
||||
right: 1rem;
|
||||
}
|
||||
.recorder{
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 8rem;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: 0 1rem 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user