mirror of
https://github.com/kevin-DL/vue-audio-recorder.git
synced 2026-01-11 19:04:28 +00:00
Refactor components
This commit is contained in:
@@ -1,65 +1,11 @@
|
|||||||
<style lang="scss">
|
|
||||||
.ar-icon-button {
|
|
||||||
fill: #747474;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid #05CBCD;
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
padding: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: .2s;
|
|
||||||
|
|
||||||
&--rec {
|
|
||||||
fill: white;
|
|
||||||
background-color: #FF6B64;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--pulse {
|
|
||||||
animation: ripple .5s linear infinite;
|
|
||||||
|
|
||||||
@keyframes ripple {
|
|
||||||
0% {
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 0 rgba(red, 0.1),
|
|
||||||
0 0 0 1px rgba(red, 0.1),
|
|
||||||
0 0 0 5px rgba(red, 0.1);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 0 rgba(red, 0.1),
|
|
||||||
0 0 0 10px rgba(red, 0.1),
|
|
||||||
0 0 0 20px rgba(red, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--clicked {
|
|
||||||
fill: white;
|
|
||||||
background-color: #05CBCD;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__sm {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__lg {
|
|
||||||
width: 45px;
|
|
||||||
height: 45px;
|
|
||||||
box-shadow: 0 2px 5px 1px rgba(158,158,158,0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="iconClasses" v-html="icons[name]"></div>
|
<div v-html="icons[name]"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
name: { type: String },
|
name: { type: String }
|
||||||
size: { type: String, default: 'sm' }
|
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
@@ -73,11 +19,6 @@
|
|||||||
volume: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
|
volume: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
iconClasses () {
|
|
||||||
return ['ar-icon-button', `ar-icon-button__${this.size}`]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.ar-line-control {
|
.ar-line-control {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #E6E6E6;
|
||||||
|
|
||||||
&__head {
|
&__head {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -12,24 +15,28 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :ref="refId" class="ar-line-control" @mousedown="onMouseDown">
|
<div
|
||||||
<div class="ar-line-control__head" :style="{width: percentageWidth}"></div>
|
:ref="refId"
|
||||||
|
class="ar-line-control"
|
||||||
|
@mousedown="onMouseDown">
|
||||||
|
<div class="ar-line-control__head" :style="calculateSize"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { calculateLineHeadPosition } from '../lib/utils.js'
|
import { calculateLineHeadPosition } from '@/lib/utils.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
refId: { type: String },
|
refId : { type: String },
|
||||||
eventName: { type: String },
|
eventName : { type: String },
|
||||||
percentage: { type: Number, default: 0 }
|
percentage : { type: Number, default: 0 },
|
||||||
|
rowDirection : { type: Boolean, default: true}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onMouseDown (ev) {
|
onMouseDown (ev) {
|
||||||
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
||||||
this.$emit('changeLineHead', seekPos)
|
this.$emit('change-linehead', seekPos)
|
||||||
document.addEventListener('mousemove', this.onMouseMove)
|
document.addEventListener('mousemove', this.onMouseMove)
|
||||||
document.addEventListener('mouseup', this.onMouseUp)
|
document.addEventListener('mouseup', this.onMouseUp)
|
||||||
},
|
},
|
||||||
@@ -37,17 +44,17 @@
|
|||||||
document.removeEventListener('mouseup', this.onMouseUp)
|
document.removeEventListener('mouseup', this.onMouseUp)
|
||||||
document.removeEventListener('mousemove', this.onMouseMove)
|
document.removeEventListener('mousemove', this.onMouseMove)
|
||||||
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
||||||
this.$emit('changeLineHead', seekPos)
|
this.$emit('change-linehead', seekPos)
|
||||||
},
|
},
|
||||||
onMouseMove (ev) {
|
onMouseMove (ev) {
|
||||||
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
let seekPos = calculateLineHeadPosition(ev, this.$refs[this.refId])
|
||||||
this.$emit('changeLineHead', seekPos)
|
this.$emit('change-linehead', seekPos)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
percentageWidth () {
|
calculateSize () {
|
||||||
let width = this.percentage < 1 ? this.percentage * 100 : this.percentage
|
let value = this.percentage < 1 ? this.percentage * 100 : this.percentage
|
||||||
return `${width}%`
|
return `${this.rowDirection ? 'width' : 'height'}: ${value}%`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.ar-player {
|
.ar-player {
|
||||||
width: 100%;
|
width: 380px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
border: 1px solid #E8E8E8;
|
border: 1px solid #E8E8E8;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
background-color: #FAFAFA;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column-reverse;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
|
||||||
|
&-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 12px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
&-actions {
|
&-actions {
|
||||||
width: 55%;
|
width: 55%;
|
||||||
@@ -17,46 +26,35 @@
|
|||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-volume {
|
&--compact {
|
||||||
display: flex;
|
height: unset;
|
||||||
align-items: center;
|
flex-direction: row;
|
||||||
line-height: 10px;
|
|
||||||
|
|
||||||
&-bar {
|
|
||||||
width: 50px;
|
|
||||||
height: 8px;
|
|
||||||
background: #E6E6E6;
|
|
||||||
border-radius: 4px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
fill: #747474;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 0;
|
|
||||||
background-color: unset;
|
background-color: unset;
|
||||||
margin-right: 3px;
|
|
||||||
|
& > .ar-player-actions {
|
||||||
|
width: unset;
|
||||||
|
|
||||||
|
& > #download,
|
||||||
|
& > #upload {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-bar {
|
& > .ar-player-bar {
|
||||||
display: flex;
|
border: 1px solid #E8E8E8;
|
||||||
align-items: center;
|
border-radius: 24px;
|
||||||
margin-bottom: 2px;
|
margin: 0 0 0 5px;
|
||||||
}
|
|
||||||
|
|
||||||
&--active {
|
& > .ar-player__progress {
|
||||||
background-color: white;
|
width: 125px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__progress {
|
&__progress {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
height: 8px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,75 +63,93 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
width: 41px;
|
width: 41px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__play {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
box-shadow: 0 2px 11px 11px rgba(0,0,0,0.07);
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
fill: white !important;
|
||||||
|
background-color: #05CBCD !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import '../scss/icons';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="ar-player" :class="{'ar-player--active': record.url}">
|
<div class="ar-player" :class="{'ar-player--compact': compact}">
|
||||||
|
|
||||||
|
<div class="ar-player-actions">
|
||||||
|
<icon-button
|
||||||
|
id="download"
|
||||||
|
class="ar-icon ar-icon__sm"
|
||||||
|
name="download"
|
||||||
|
@click.native="download"/>
|
||||||
|
|
||||||
|
<icon-button
|
||||||
|
id="play"
|
||||||
|
class="ar-icon ar-icon__lg ar-player__play"
|
||||||
|
:name="playBtnIcon"
|
||||||
|
:class="{'ar-player__play--active': isPlaying}"
|
||||||
|
@click.native="playback"/>
|
||||||
|
|
||||||
|
<icon-button
|
||||||
|
id="upload"
|
||||||
|
class="ar-icon ar-icon__sm"
|
||||||
|
name="save"
|
||||||
|
@click.native="upload"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="ar-player-bar">
|
<div class="ar-player-bar">
|
||||||
|
|
||||||
<div class="ar-player__time">{{playedTime}}</div>
|
<div class="ar-player__time">{{playedTime}}</div>
|
||||||
|
|
||||||
<line-control
|
<line-control
|
||||||
class="ar-player__progress"
|
class="ar-player__progress"
|
||||||
ref-id="progress"
|
ref-id="progress"
|
||||||
:percentage="progress"
|
:percentage="progress"
|
||||||
@changeLineHead="_onUpdateProgress"/>
|
@change-linehead="_onUpdateProgress"/>
|
||||||
|
|
||||||
<div class="ar-player__time">{{duration}}</div>
|
<div class="ar-player__time">{{duration}}</div>
|
||||||
|
<volume-control @change-volume="_onChangeVolume"/>
|
||||||
<div class="ar-player-volume">
|
|
||||||
<icon-button class="ar-player-volume__icon" name="volume"/>
|
|
||||||
<line-control
|
|
||||||
class="ar-player-volume-bar"
|
|
||||||
ref-id="volume"
|
|
||||||
:percentage="volume"
|
|
||||||
@changeLineHead="_onUpdateVolume"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ar-player-actions">
|
<audio :id="playerUniqId" :src="audioSource"></audio>
|
||||||
<icon-button name="download" @click.native="download"/>
|
|
||||||
<icon-button
|
|
||||||
size="lg"
|
|
||||||
:name="playBtnIcon"
|
|
||||||
:class="{'ar-icon-button--clicked': isPlaying}"
|
|
||||||
@click.native="playback"/>
|
|
||||||
<icon-button name="save" @click.native="upload"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<audio id="audio-recorder-player" :src="record.url"></audio>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import IconButton from './icon-button.vue'
|
import IconButton from './icon-button'
|
||||||
import LineControl from './line-control.vue'
|
import LineControl from './line-control'
|
||||||
import { convertTimeMMSS } from '../lib/utils.js'
|
import VolumeControl from './volume-control'
|
||||||
|
import { convertTimeMMSS } from '@/lib/utils.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
uploadUrl: { type: String },
|
src : { type: String },
|
||||||
record: { type: Object },
|
uploadUrl : { type: String },
|
||||||
startUpload: { type: Function },
|
record : { type: Object },
|
||||||
successfulUpload: { type: Function },
|
compact : { type: Boolean, default: true },
|
||||||
failedUpload: { type: Function }
|
startUpload : { type: Function },
|
||||||
|
successfulUpload : { type: Function },
|
||||||
|
failedUpload : { type: Function }
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
duration: convertTimeMMSS(0),
|
duration: convertTimeMMSS(0),
|
||||||
playedTime: convertTimeMMSS(0),
|
playedTime: convertTimeMMSS(0),
|
||||||
progress: 0,
|
progress: 0
|
||||||
volume: 0.8
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
IconButton,
|
IconButton,
|
||||||
LineControl
|
LineControl,
|
||||||
|
VolumeControl
|
||||||
},
|
},
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
this.player = document.getElementById('audio-recorder-player')
|
this.player = document.getElementById(this.playerUniqId)
|
||||||
|
|
||||||
this.player.addEventListener('ended', () => {
|
this.player.addEventListener('ended', () => {
|
||||||
this.isPlaying = false
|
this.isPlaying = false
|
||||||
@@ -149,11 +165,17 @@
|
|||||||
computed: {
|
computed: {
|
||||||
playBtnIcon () {
|
playBtnIcon () {
|
||||||
return this.isPlaying ? 'pause' : 'play'
|
return this.isPlaying ? 'pause' : 'play'
|
||||||
|
},
|
||||||
|
audioSource () {
|
||||||
|
return this.src || this.record.url
|
||||||
|
},
|
||||||
|
playerUniqId () {
|
||||||
|
return `audio-player${this._uid}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
playback () {
|
playback () {
|
||||||
if (!this.record.url) {
|
if (!this.audioSource) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +188,7 @@
|
|||||||
this.isPlaying = !this.isPlaying
|
this.isPlaying = !this.isPlaying
|
||||||
},
|
},
|
||||||
upload () {
|
upload () {
|
||||||
if (!this.record.url) {
|
if (!this.audioSource) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +216,7 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
download () {
|
download () {
|
||||||
if (!this.record.url) {
|
if (!this.audioSource) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,10 +238,9 @@
|
|||||||
this.player.currentTime = pos * this.player.duration
|
this.player.currentTime = pos * this.player.duration
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_onUpdateVolume (val) {
|
_onChangeVolume (val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
this.player.volume = val
|
this.player.volume = val
|
||||||
this.volume = val
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +145,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import '../scss/icons';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -160,15 +162,15 @@
|
|||||||
<div class="ar-content" :class="{'ar__blur': isUploading}">
|
<div class="ar-content" :class="{'ar__blur': isUploading}">
|
||||||
<div class="ar-recorder">
|
<div class="ar-recorder">
|
||||||
<icon-button
|
<icon-button
|
||||||
size="lg"
|
class="ar-icon ar-icon__lg"
|
||||||
:name="iconButtonType"
|
:name="iconButtonType"
|
||||||
:class="{
|
:class="{
|
||||||
'ar-icon-button--rec': isRecording,
|
'ar-icon--rec': isRecording,
|
||||||
'ar-icon-button--pulse': isRecording && volume > 0.02
|
'ar-icon--pulse': isRecording && volume > 0.02
|
||||||
}"
|
}"
|
||||||
@click.native="toggleRecorder"/>
|
@click.native="toggleRecorder"/>
|
||||||
<icon-button
|
<icon-button
|
||||||
class="ar-recorder__stop"
|
class="ar-icon ar-icon__sm ar-recorder__stop"
|
||||||
name="stop"
|
name="stop"
|
||||||
@click.native="stopRecorder"/>
|
@click.native="stopRecorder"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -188,14 +190,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<record-player
|
<audio-player
|
||||||
|
:compact="compact"
|
||||||
:record="selectedRecord"
|
:record="selectedRecord"
|
||||||
:upload-url="uploadUrl"
|
:upload-url="uploadUrl"
|
||||||
:start-upload="startUpload"
|
:start-upload="startUpload"
|
||||||
:successful-upload="successfulUpload"
|
:successful-upload="successfulUpload"
|
||||||
:failed-upload="failedUpload"
|
:failed-upload="failedUpload"
|
||||||
@on-start-upload="onStartUpload"
|
@start-upload="onStartUpload"
|
||||||
@on-end-upload="onEndUpload"/>
|
@end-upload="onEndUpload"/>
|
||||||
|
|
||||||
<div :class="uploadStatusClasses" v-if="uploadStatus">{{message}}</div>
|
<div :class="uploadStatusClasses" v-if="uploadStatus">{{message}}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,27 +206,28 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import IconButton from './components/icon-button.vue'
|
import AudioPlayer from './player.vue'
|
||||||
import Recorder from './lib/recorder.js'
|
import IconButton from './icon-button.vue'
|
||||||
import RecordPlayer from './components/record-player.vue'
|
import Recorder from '@/lib/recorder.js'
|
||||||
import { convertTimeMMSS } from './lib/utils.js'
|
import { convertTimeMMSS } from '@/lib/utils.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
attempts: { type: Number },
|
attempts : { type: Number },
|
||||||
time: { type: Number },
|
compact : { type: Boolean, default: false },
|
||||||
uploadUrl: { type: String },
|
time : { type: Number },
|
||||||
|
uploadUrl : { type: String },
|
||||||
|
|
||||||
attemptsLimit: { type: Function },
|
attemptsLimit : { type: Function },
|
||||||
failedUpload: { type: Function },
|
failedUpload : { type: Function },
|
||||||
micFailed: { type: Function },
|
micFailed : { type: Function },
|
||||||
startRecord: { type: Function },
|
startRecord : { type: Function },
|
||||||
startUpload: { type: Function },
|
startUpload : { type: Function },
|
||||||
stopRecord: { type: Function },
|
stopRecord : { type: Function },
|
||||||
successfulUpload: { type: Function },
|
successfulUpload : { type: Function },
|
||||||
|
|
||||||
successfulUploadMsg: { type: String, default: 'Upload successful' },
|
successfulUploadMsg : { type: String, default: 'Upload successful' },
|
||||||
failedUploadMsg: { type: String, default: 'Upload fail' }
|
failedUploadMsg : { type: String, default: 'Upload fail' }
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -245,8 +249,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
IconButton,
|
AudioPlayer,
|
||||||
RecordPlayer
|
IconButton
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleRecorder () {
|
toggleRecorder () {
|
||||||
60
src/components/volume-control.vue
Normal file
60
src/components/volume-control.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<style lang="scss">
|
||||||
|
.ar-volume {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 10px;
|
||||||
|
|
||||||
|
&-bar {
|
||||||
|
width: 50px;
|
||||||
|
height: 6px;
|
||||||
|
background: #E6E6E6;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
fill: #747474;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: unset;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="ar-volume">
|
||||||
|
<icon-button class="ar-volume__icon" name="volume"/>
|
||||||
|
<line-control
|
||||||
|
class="ar-volume-bar"
|
||||||
|
ref-id="volume"
|
||||||
|
:percentage="volume"
|
||||||
|
@change-linehead="onChangeLinehead"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import IconButton from './icon-button.vue'
|
||||||
|
import LineControl from './line-control.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
volume: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
IconButton,
|
||||||
|
LineControl
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChangeLinehead (val) {
|
||||||
|
this.$emit('change-volume', val)
|
||||||
|
this.volume = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
15
src/index.js
15
src/index.js
@@ -1,13 +1,22 @@
|
|||||||
import AudioRecorder from './audio-recorder.vue'
|
import AudioPlayer from './components/player.vue'
|
||||||
|
import AudioRecorder from './components/recorder.vue'
|
||||||
|
|
||||||
export default {
|
const components = {
|
||||||
install: function (Vue) {
|
AudioPlayer,
|
||||||
|
AudioRecorder,
|
||||||
|
|
||||||
|
install (Vue) {
|
||||||
if (this.installed) {
|
if (this.installed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.installed = true
|
this.installed = true
|
||||||
|
|
||||||
|
Vue.component('audio-player', AudioPlayer)
|
||||||
Vue.component('audio-recorder', AudioRecorder)
|
Vue.component('audio-recorder', AudioRecorder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default components
|
||||||
|
|
||||||
|
export { AudioPlayer, AudioRecorder }
|
||||||
|
|||||||
45
src/scss/icons.scss
Normal file
45
src/scss/icons.scss
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
.ar-icon {
|
||||||
|
fill: #747474;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #05CBCD;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .2s;
|
||||||
|
|
||||||
|
&--rec {
|
||||||
|
fill: white;
|
||||||
|
background-color: #FF6B64;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pulse {
|
||||||
|
animation: ripple .5s linear infinite;
|
||||||
|
|
||||||
|
@keyframes ripple {
|
||||||
|
0% {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 0 rgba(red, 0.1),
|
||||||
|
0 0 0 1px rgba(red, 0.1),
|
||||||
|
0 0 0 5px rgba(red, 0.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 0 rgba(red, 0.1),
|
||||||
|
0 0 0 10px rgba(red, 0.1),
|
||||||
|
0 0 0 20px rgba(red, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sm {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__lg {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
box-shadow: 0 2px 5px 1px rgba(158,158,158,0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user