input item enhancements
This commit is contained in:
parent
9eca20a2a3
commit
eff3c808ba
12 changed files with 195 additions and 163 deletions
|
|
@ -55,12 +55,7 @@ const onMessage = (messageStr: string): void => {
|
||||||
|
|
||||||
// Check to see if this is a Render Message.
|
// Check to see if this is a Render Message.
|
||||||
if (m.content) {
|
if (m.content) {
|
||||||
message = renderMessage({
|
message = renderMessage(m.content.text, m.content.audio, m.context, m.modifier);
|
||||||
text: m.content.text,
|
|
||||||
audio: m.content.audio,
|
|
||||||
context: m.context,
|
|
||||||
modifier: m.modifier,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Play audio if any.
|
// Play audio if any.
|
||||||
if (message.content.audio) {
|
if (message.content.audio) {
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,62 @@
|
||||||
import { onMounted } from "vue";
|
import anime from "animejs";
|
||||||
|
import { onMounted, onUnmounted, ref, Ref } from "vue";
|
||||||
import useMitt from "@/modules/mitt";
|
import useMitt from "@/modules/mitt";
|
||||||
import { useIpc } from '@/modules/ipc';
|
import { useIpc } from '@/modules/ipc';
|
||||||
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
||||||
import { renderMessage } from '@/modules/message';
|
import { renderMessage } from '@/modules/message';
|
||||||
|
|
||||||
|
|
||||||
|
function showRecIcon () {
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: '#recIcon',
|
||||||
|
opacity: [0, 0.75],
|
||||||
|
scale: [0.0, 1],
|
||||||
|
duration: 250,
|
||||||
|
easing: 'linear',
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideRecIcon () {
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: '#recIcon',
|
||||||
|
opacity: [0.75, 0],
|
||||||
|
scale: [1, 0],
|
||||||
|
duration: 250,
|
||||||
|
easing: 'linear',
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default function useAudioInputController (typing: Ref) {
|
||||||
|
|
||||||
export default function useAudioInputController () {
|
|
||||||
|
|
||||||
// For sending messages.
|
// For sending messages.
|
||||||
const { post } = useIpc();
|
const { post } = useIpc();
|
||||||
const { emitter } = useMitt();
|
const { emitter } = useMitt();
|
||||||
|
|
||||||
// Keepp track of when we are recording.
|
// Keepp track of when we are recording.
|
||||||
let recording = false;
|
const recording = ref(false);
|
||||||
|
|
||||||
// Utility function to render message.
|
|
||||||
const render = (text: string, audio: boolean | string, context: string, modifier: string): string => {
|
|
||||||
const m = renderMessage({ text, audio, context, modifier });
|
|
||||||
emitter.emit("self-message", m);
|
|
||||||
return m.uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---Callbacks-----------------------------------------------
|
//---Callbacks-----------------------------------------------
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
const cmd = keyboardNameMap[e.keyCode];
|
const cmd = keyboardNameMap[e.keyCode];
|
||||||
|
// console.log(cmd)
|
||||||
|
|
||||||
// Start recording on space bar.
|
// Start recording on space bar.
|
||||||
if (cmd == "SPACE" && !recording) {
|
if (cmd == "SPACE" && !recording.value && !typing.value) {
|
||||||
|
|
||||||
post('update-recorder', {
|
post('update-recorder', {
|
||||||
isRecording: true,
|
isRecording: true,
|
||||||
uid: null
|
uid: null
|
||||||
});
|
});
|
||||||
|
|
||||||
recording = true;
|
showRecIcon()
|
||||||
|
recording.value = true;
|
||||||
|
console.log("Recording...")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,17 +66,20 @@ export default function useAudioInputController () {
|
||||||
const cmd = keyboardNameMap[e.keyCode];
|
const cmd = keyboardNameMap[e.keyCode];
|
||||||
|
|
||||||
// Stop recording on space up.
|
// Stop recording on space up.
|
||||||
if (cmd == "SPACE" && recording) {
|
if (cmd == "SPACE" && recording.value) {
|
||||||
|
|
||||||
// Render audio immediately.
|
// Render audio immediately.
|
||||||
const uid = render("", "", "", "sf");
|
const message = renderMessage("", "", "", "sf")
|
||||||
|
emitter.emit("self-message", message);
|
||||||
|
|
||||||
post('update-recorder', {
|
post('update-recorder', {
|
||||||
isRecording: false,
|
isRecording: false,
|
||||||
uid: uid
|
uid: message.uid
|
||||||
});
|
});
|
||||||
|
|
||||||
recording = false;
|
hideRecIcon()
|
||||||
|
recording.value = false;
|
||||||
|
console.log("Stopping record...")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,6 +92,12 @@ export default function useAudioInputController () {
|
||||||
window.addEventListener("keyup", onKeyUp);
|
window.addEventListener("keyup", onKeyUp);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener("keydown", onKeyDown);
|
||||||
|
window.removeEventListener("keyup", onKeyUp);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
recording
|
recording
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
import anime from "animejs";
|
import anime from "animejs";
|
||||||
import useMitt from "@/modules/mitt";
|
import useMitt from "@/modules/mitt";
|
||||||
import { useIpc } from '@/modules/ipc';
|
import { useIpc } from '@/modules/ipc';
|
||||||
import { Ref, watch, onMounted } from "vue";
|
import { Ref, ref, watch, onMounted, onUnmounted } from "vue";
|
||||||
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
||||||
import { clientMessage, renderMessage } from '@/modules/message';
|
import { clientMessage, renderMessage } from '@/modules/message';
|
||||||
|
|
||||||
// Post a message to the backend.
|
|
||||||
const { post } = useIpc();
|
|
||||||
|
|
||||||
|
|
||||||
//---Animations-----------------------------------------------
|
//---Animations-----------------------------------------------
|
||||||
|
|
||||||
let side = "right"; // Side of parent we are on.
|
let side = "right"; // Side of parent we are on.
|
||||||
let visible = false; // Whether textInput is visible.
|
|
||||||
|
|
||||||
function showTextInput () {
|
function showTextInput () {
|
||||||
const t1 = (side === "right") ? 50 : -70;
|
const t1 = (side === "right") ? 50 : -70;
|
||||||
|
|
@ -27,7 +22,6 @@ function showTextInput () {
|
||||||
easing: 'easeOutExpo',
|
easing: 'easeOutExpo',
|
||||||
})
|
})
|
||||||
|
|
||||||
visible = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideTextInput() {
|
function hideTextInput() {
|
||||||
|
|
@ -35,14 +29,13 @@ function hideTextInput() {
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: '#textInput',
|
targets: '#textInput',
|
||||||
opacity: 0,
|
opacity: [1, 0],
|
||||||
translateX: t,
|
translateX: t,
|
||||||
scale: 0.3,
|
scale: 0.3,
|
||||||
duration: 500,
|
duration: 500,
|
||||||
easing: 'easeOutExpo',
|
easing: 'easeOutExpo',
|
||||||
})
|
})
|
||||||
|
|
||||||
visible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchSide(currentSide: string) {
|
function switchSide(currentSide: string) {
|
||||||
|
|
@ -63,27 +56,29 @@ function switchSide(currentSide: string) {
|
||||||
export default function useTextInputController(elementX: Ref) {
|
export default function useTextInputController(elementX: Ref) {
|
||||||
let textInput: HTMLInputElement | null;
|
let textInput: HTMLInputElement | null;
|
||||||
|
|
||||||
let length: number;
|
|
||||||
|
|
||||||
// For sending messages.
|
|
||||||
const { post } = useIpc();
|
const { post } = useIpc();
|
||||||
const { emitter } = useMitt();
|
const { emitter } = useMitt();
|
||||||
|
|
||||||
// Keep track of first key press.
|
|
||||||
let firstKey = true;
|
let firstKey = true;
|
||||||
|
const typing = ref(false);
|
||||||
|
|
||||||
// Clear text input.
|
// Prep inputItem for typing.
|
||||||
const clearInput = () => {
|
const prepInput = () => {
|
||||||
if (textInput) textInput.value = "";
|
showTextInput()
|
||||||
hideTextInput()
|
typing.value = true
|
||||||
firstKey = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility function to render message.
|
// Clear and hide inputItem after done typing.
|
||||||
const render = (text: string, audio: boolean | string, context: string, modifier: string): string => {
|
const clearInput = () => {
|
||||||
const m = renderMessage({ text, audio, context, modifier });
|
|
||||||
emitter.emit("self-message", m);
|
if (textInput) {
|
||||||
return m.uid;
|
textInput.value = "";
|
||||||
|
textInput.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
hideTextInput()
|
||||||
|
firstKey = true;
|
||||||
|
typing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message and clean up after.
|
// Send a message and clean up after.
|
||||||
|
|
@ -91,50 +86,53 @@ export default function useTextInputController(elementX: Ref) {
|
||||||
if (textInput) {
|
if (textInput) {
|
||||||
|
|
||||||
// Render message
|
// Render message
|
||||||
const uid = render(textInput.value, false, "", "sf");
|
const message = renderMessage(textInput.value, false, "", "sf")
|
||||||
|
emitter.emit("self-message", message);
|
||||||
|
|
||||||
// Send it to the backend for processing.
|
// Send it to the backend for processing.
|
||||||
const clientM = clientMessage(textInput.value, false, uid);
|
const clientM = clientMessage(textInput.value, false, message.uid);
|
||||||
post('client-message', clientM);
|
post('client-message', clientM);
|
||||||
|
|
||||||
|
clearInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---Callbacks-----------------------------------------------
|
//---Callbacks-----------------------------------------------
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const key = keyboardNameMap[e.keyCode]
|
||||||
|
console.log(key)
|
||||||
|
|
||||||
if (textInput) {
|
if (textInput) {
|
||||||
const key = keyboardNameMap[e.keyCode]
|
|
||||||
|
|
||||||
// Reveal textInput on first key press.
|
// First-key handler.
|
||||||
if (firstKey) {
|
if (firstKey) {
|
||||||
|
if (key == "SPACE") return
|
||||||
// Handle for space bar
|
prepInput()
|
||||||
if (key == "SPACE") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
showTextInput()
|
|
||||||
firstKey = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
textInput.focus();
|
textInput.focus();
|
||||||
|
|
||||||
|
// Close input when no text or on ESC.
|
||||||
if (textInput.value == "" && !firstKey) {
|
if (textInput.value == "" && !firstKey) {
|
||||||
clearInput()
|
clearInput()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == "ENTER") {
|
if (key === "ESCAPE") {
|
||||||
|
clearInput()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close and send on enter.
|
||||||
|
if (key === "ENTER") {
|
||||||
if (textInput.value) {
|
if (textInput.value) {
|
||||||
sendMessage()
|
sendMessage()
|
||||||
clearInput()
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == "ESCAPE") {
|
if (firstKey) firstKey = false
|
||||||
clearInput()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,8 +164,12 @@ export default function useTextInputController(elementX: Ref) {
|
||||||
window.addEventListener("keydown", onKeyDown);
|
window.addEventListener("keydown", onKeyDown);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener("keydown", onKeyDown);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
typing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,9 @@
|
||||||
>
|
>
|
||||||
AG
|
AG
|
||||||
|
|
||||||
<!-- Show audio input on spacebar -->
|
<!-- Recording animation on space bar -->
|
||||||
<AudioInput />
|
|
||||||
|
|
||||||
|
|
||||||
<span v-if="recording" class="play"></span>
|
<span v-if="recording" class="play"></span>
|
||||||
<span v-if="recording" class="pause">
|
<span v-if="recording" class="pause"></span>
|
||||||
<div class="rec-icon"></div>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<!-- Show text input on key-down -->
|
<!-- Show text input on key-down -->
|
||||||
<TextInput />
|
<TextInput />
|
||||||
|
|
@ -43,12 +38,19 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
|
||||||
|
// Initial position.
|
||||||
|
const xStart = 15;
|
||||||
|
const yStart = window.innerHeight - 200;
|
||||||
|
|
||||||
// Calculate position of inputItem on drag.
|
// Calculate position of inputItem on drag.
|
||||||
const { elementX, elementY } = draggify({ elementId: "inputItem" });
|
const { elementX, elementY } = draggify(
|
||||||
|
{ elementId: "inputItem" },
|
||||||
|
{ x: xStart, y: yStart }
|
||||||
|
);
|
||||||
|
|
||||||
// Controllers for text and audio.
|
// Controllers for text and audio.
|
||||||
useTextInputController(elementX)
|
const { typing } = useTextInputController(elementX)
|
||||||
const { recording } = useAudioInputController()
|
const { recording } = useAudioInputController(typing)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elementX,
|
elementX,
|
||||||
|
|
@ -64,8 +66,6 @@ export default defineComponent({
|
||||||
.input-item {
|
.input-item {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
opacity: 1.0;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -80,7 +80,8 @@ export default defineComponent({
|
||||||
// border: 4px solid #C6C6C6;
|
// border: 4px solid #C6C6C6;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|
||||||
background-color: #EBEBEB;
|
// Set opacity here to not affect child.
|
||||||
|
background-color: rgba(235, 235, 235, 0.75);
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch } from "vue";
|
import { defineComponent } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "TextInput",
|
name: "TextInput",
|
||||||
|
|
@ -46,15 +46,4 @@ export default defineComponent({
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes appear {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(50px) scale(0.3);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(110px) scale(1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -30,7 +30,7 @@ function calcPosition (elementPosition: number, percent: number,
|
||||||
return elementPosition
|
return elementPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function draggify(input: { elementId: string }) {
|
export default function draggify(input: { elementId: string }, initPosition: { x: number; y: number}) {
|
||||||
|
|
||||||
let element: HTMLElement | null;
|
let element: HTMLElement | null;
|
||||||
|
|
||||||
|
|
@ -113,8 +113,8 @@ export default function draggify(input: { elementId: string }) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the coordinants.
|
// Initialize the coordinants.
|
||||||
elementX.value = 15;
|
elementX.value = initPosition.x;
|
||||||
elementY.value = 300;
|
elementY.value = initPosition.y;
|
||||||
|
|
||||||
// remove event listeners on component dismount.
|
// remove event listeners on component dismount.
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,20 @@
|
||||||
import { RenderMessage, ClientMessage } from "@/types/message/index";
|
import { RenderMessage, ClientMessage } from "@/types/message/index";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
interface RenderParams {
|
|
||||||
text: string;
|
|
||||||
audio: boolean | string;
|
|
||||||
context: string;
|
|
||||||
modifier: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTimeStamp(): number {
|
function getTimeStamp(): number {
|
||||||
const currentdate = new Date();
|
const currentdate = new Date();
|
||||||
return currentdate.getTime();
|
return currentdate.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a RenderMessage object.
|
// Create a RenderMessage object.
|
||||||
export const renderMessage = (params: RenderParams): RenderMessage => (
|
export const renderMessage = (text: boolean | string, audio: boolean | string, context: string, modifier: string): RenderMessage => (
|
||||||
{
|
{
|
||||||
content: {
|
content: {
|
||||||
text: params.text,
|
text: text,
|
||||||
audio: params.audio
|
audio: audio
|
||||||
},
|
},
|
||||||
context: params.context,
|
context: context,
|
||||||
modifier: params.modifier,
|
modifier: modifier,
|
||||||
time: getTimeStamp(),
|
time: getTimeStamp(),
|
||||||
uid: uuidv4(),
|
uid: uuidv4(),
|
||||||
isChild: "none"
|
isChild: "none"
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,16 @@ export default function useMessages() {
|
||||||
updateScrollRef()
|
updateScrollRef()
|
||||||
|
|
||||||
// update message if in the map.
|
// update message if in the map.
|
||||||
const m = messages.value.get(a.uid)
|
const message = messages.value.get(a.uid)
|
||||||
m.context = a.context
|
message.context = a.context
|
||||||
m.text = a.text
|
message.content.text = a.text
|
||||||
|
|
||||||
setTimeout(adjustScroll, 10);
|
setTimeout(adjustScroll, 10);
|
||||||
|
|
||||||
return m
|
console.log(`Annotation: ${a.text}`)
|
||||||
|
console.log(`Annotation: ${a.context}`)
|
||||||
|
|
||||||
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveMessages = () => {
|
const saveMessages = () => {
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,3 @@ export default function useMitt() {
|
||||||
emitter
|
emitter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export interface UserCreds {
|
||||||
|
|
||||||
export interface RenderMessage {
|
export interface RenderMessage {
|
||||||
content: {
|
content: {
|
||||||
text: string;
|
text: boolean | string;
|
||||||
audio: boolean | string;
|
audio: boolean | string;
|
||||||
};
|
};
|
||||||
context: string;
|
context: string;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
<InputItem />
|
<InputItem />
|
||||||
<Settings />
|
<Settings />
|
||||||
|
|
||||||
|
<div id="recIcon" />
|
||||||
|
|
||||||
<!-- List of message bubbles. -->
|
<!-- List of message bubbles. -->
|
||||||
<div id="messenger">
|
<div id="messenger">
|
||||||
<MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" />
|
<MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" />
|
||||||
|
|
@ -109,4 +111,26 @@ export default defineComponent({
|
||||||
#messenger::-webkit-scrollbar {
|
#messenger::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#recIcon {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.0);
|
||||||
|
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-right: 66px;
|
||||||
|
|
||||||
|
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #FF3B3B;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue