// send message on ENTER.
const onEnter = () => {
+
if (input.value) {
// remove first character of input.
const text = input.value.substring(1);
if (textInput) textInput.value = '';
input.value = " ";
}
+
}
// update input on keydown event & listen for special commands.
const onKeyDown = (e: KeyboardEvent) => {
+
if (textInput) textInput.focus();
// keyboardCharMap is an array of arrays, with each inner
if (e.shiftKey) {
iCol = 1;
}
+
const ch = keyboardCharMap[e.keyCode][iCol];
// Optionally do things with non-printables,
default:
input.value += ch;
}
+
}
// stop stream recording and render audio message on space key up event.
// watch keyboard input & update current state.
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;
});
return;
}
+
isTyping.value = true;
+
});
return {
:class="{ playing: isRecording }"
:style="{ top: `${elementY}px`, left: `${elementX}px` }"
>
+
+ <!-- animations for recording and on-standby -->
<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>
+ <span v-if="isRecording" class="pause">
+ <div class="rec-icon"></div>
+ </span>
+
+ <!-- Show text input on key-down -->
+ <input id="textInput" type="text" v-show="isTyping && input.length > 0"/>
+
</div>
</template>
<script lang="ts">
+
import { defineComponent } from "vue";
import draggify from "@/modules/draggify";
import useInputController from "./inputController";
export default defineComponent({
name: "InputItem",
setup() {
+
+ // Calculate position of inputItem on drag.
const { elementX, elementY } = draggify({ elementId: "inputItem" });
+
+ //
const { input, isRecording, isTyping } = useInputController();
return {
</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;
+
+#textInput {
+ width: 150px;
+ height: 36px;
+
+ border-top-right-radius: 18px;
+ border-bottom-right-radius: 18px;
+
+ padding: 0;
+ margin-left: 18px;
+
+ outline: none;
+ border: none;
+ pointer-events: none;
+ animation-name: expand;
+ animation-duration: 0.5s;
+}
+
+@keyframes expand {
+ from {
+ width: 0px;
+ }
+ to {
+ width: 150px;
+ }
+}
+
+.rec-icon {
+ width: 8px;
+ height: 8px;
+ border-radius: 4px;
+ background-color: red;
+ transform: translate(14px);
+
+ animation-name: rec;
+ animation-duration: 0.5s;
+}
+
+@keyframes rec {
+ from {
+ transform: translate(14px) scale(0.3);
+ }
+ to {
+ transform: translate(14px) scale(1.0);
}
}
.input-item {
position: absolute;
- width: 30px;
- height: 30px;
+ display: flex;
+ align-items: center;
- border-radius: 19px;
+ padding: 0;
- z-index: 20;
+ width: 36px;
+ height: 36px;
- top: 200px;
- right: 0px;
+ border-radius: 18px;
+
+ z-index: 20;
background-color: white;
- border: 4px solid #C3C3C3;
cursor: pointer;
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.45);
}
}
+
</style>