inputItem v1
This commit is contained in:
parent
38fc1a1b5f
commit
f2a240d803
18 changed files with 249 additions and 1072 deletions
80
src/components/inputItem/inputController.ts
Normal file
80
src/components/inputItem/inputController.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Controls which input to visualize
|
||||
* Will visualize text input by default as user types or
|
||||
* if user holds space bar down, input audio stream
|
||||
* will be visualized & recorded
|
||||
*/
|
||||
|
||||
import { ref, watch, onUnmounted, onMounted } from "vue";
|
||||
import useKeyDownHandler from "@/modules/keyDownHandler/useKeyDownHandler";
|
||||
import useMitt from "@/modules/mitt";
|
||||
import { useIpc } from '@/modules/ipc';
|
||||
|
||||
export default function useInputController() {
|
||||
const isRecording = ref(false);
|
||||
const isTyping = ref(false);
|
||||
const { emitter } = useMitt();
|
||||
const { post } = useIpc();
|
||||
|
||||
// send message on ENTER
|
||||
const enterCallback = (input: string) => {
|
||||
|
||||
const message = {
|
||||
audio: 0,
|
||||
text: input
|
||||
};
|
||||
|
||||
// trigger send animation
|
||||
emitter.emit("animate-send");
|
||||
|
||||
// send message to backend
|
||||
if (input) post('message', message);
|
||||
}
|
||||
|
||||
const { keyDownHandler, input } = useKeyDownHandler(enterCallback);
|
||||
|
||||
// stops stream recording on space key up
|
||||
function keyupHandler(e: any) {
|
||||
if (e.key === " " && isRecording.value) {
|
||||
|
||||
isRecording.value = false;
|
||||
post('update-recorder', isRecording.value);
|
||||
input.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// add window event keyboard listeners
|
||||
window.addEventListener("keydown", keyDownHandler);
|
||||
window.addEventListener('keyup', keyupHandler);
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("keydown", keyDownHandler);
|
||||
window.removeEventListener("keyup", keyupHandler);
|
||||
});
|
||||
|
||||
// determine whether to render text or audio based one the keyboard input
|
||||
watch(input, (input, prevInput) => {
|
||||
if (prevInput !== "" || prevInput.length > 0) {
|
||||
if (!isRecording.value) {
|
||||
isTyping.value = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (input === " " && isRecording.value === false) {
|
||||
// isTyping.value = false;
|
||||
isRecording.value = true;
|
||||
post('update-recorder', isRecording.value);
|
||||
return;
|
||||
}
|
||||
isTyping.value = true;
|
||||
});
|
||||
|
||||
return {
|
||||
input,
|
||||
isRecording,
|
||||
isTyping
|
||||
}
|
||||
|
||||
}
|
||||
177
src/components/inputItem/inputItem.vue
Normal file
177
src/components/inputItem/inputItem.vue
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
<template>
|
||||
<div
|
||||
id="inputItem"
|
||||
class="input-item"
|
||||
:class="{ playing: isRecording }"
|
||||
:style="{ top: `${elementY}px`, left: `${elementX}px` }"
|
||||
>
|
||||
<span v-if="isRecording" class="play"></span>
|
||||
<span v-if="isRecording" class="pause"></span>
|
||||
<div class="text-input" v-show="isTyping && input.length > 0">
|
||||
<div class="initials">A</div>
|
||||
<input id="textInput" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import draggify from "@/modules/draggify";
|
||||
import useInputController from "./inputController";
|
||||
|
||||
export default defineComponent({
|
||||
name: "InputItem",
|
||||
setup() {
|
||||
const { elementX, elementY } = draggify({ elementId: "inputItem" });
|
||||
const { input, isRecording, isTyping } = useInputController();
|
||||
|
||||
return {
|
||||
elementX,
|
||||
elementY,
|
||||
isRecording,
|
||||
isTyping,
|
||||
input,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text-input {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
left: 50%;
|
||||
background-color: #fff;
|
||||
transform: translate(-12%, -50%);
|
||||
border-radius: 25px;
|
||||
input {
|
||||
border-top-right-radius: 25px;
|
||||
border-bottom-right-radius: 25px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
outline: none;
|
||||
border: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
.initials {
|
||||
border-radius: 50%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.input-item {
|
||||
position: absolute;
|
||||
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
border-radius: 19px;
|
||||
|
||||
z-index: 20;
|
||||
|
||||
top: 200px;
|
||||
right: 0px;
|
||||
|
||||
background-color: white;
|
||||
border: 4px solid #C3C3C3;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
.play,
|
||||
.pause {
|
||||
z-index: 5;
|
||||
&::before,
|
||||
&::after {
|
||||
-webkit-border-radius: 1000px;
|
||||
-moz-border-radius: 1000px;
|
||||
border-radius: 1000px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 2.35em;
|
||||
width: 2.35em;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
.play::before {
|
||||
box-shadow: 0 0 0 rgba(195, 195, 195, 0);
|
||||
}
|
||||
.pause {
|
||||
opacity: 0;
|
||||
}
|
||||
&.playing {
|
||||
.play {
|
||||
opacity: 0;
|
||||
}
|
||||
.pause {
|
||||
opacity: 1;
|
||||
&::before {
|
||||
-moz-animation: audio1 1.5s infinite ease-in-out;
|
||||
-o-animation: audio1 1.5s infinite ease-in-out;
|
||||
-webkit-animation: audio1 1.5s infinite ease-in-out;
|
||||
animation: audio1 1.5s infinite ease-in-out;
|
||||
}
|
||||
&::after {
|
||||
-moz-animation: audio2 2.2s infinite ease-in-out;
|
||||
-o-animation: audio2 2.2s infinite ease-in-out;
|
||||
-webkit-animation: audio2 2.2s infinite ease-in-out;
|
||||
animation: audio2 2.2s infinite ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.animate-audio1 {
|
||||
-moz-animation: audio1 1.5s infinite ease-in-out;
|
||||
-o-animation: audio1 1.5s infinite ease-in-out;
|
||||
-webkit-animation: audio1 1.5s infinite ease-in-out;
|
||||
animation: audio1 1.5s infinite ease-in-out;
|
||||
}
|
||||
@keyframes audio1 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25);
|
||||
}
|
||||
}
|
||||
.animate-audio2 {
|
||||
-moz-animation: audio2 2.2s infinite ease-in-out;
|
||||
-o-animation: audio2 2.2s infinite ease-in-out;
|
||||
-webkit-animation: audio2 2.2s infinite ease-in-out;
|
||||
animation: audio2 2.2s infinite ease-in-out;
|
||||
}
|
||||
@keyframes audio2 {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.05);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.45);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in a new issue