improvments
This commit is contained in:
parent
224f502f1c
commit
a6ebab0dea
8 changed files with 303 additions and 332 deletions
78
src/components/inputItem/controllers/audioCtrl.ts
Normal file
78
src/components/inputItem/controllers/audioCtrl.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import useMitt from "@/modules/mitt";
|
||||||
|
import { useIpc } from '@/modules/ipc';
|
||||||
|
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
||||||
|
import { renderMessage } from '@/modules/message';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function useAudioInputController () {
|
||||||
|
|
||||||
|
// For sending messages.
|
||||||
|
const { post } = useIpc();
|
||||||
|
const { emitter } = useMitt();
|
||||||
|
|
||||||
|
// Keepp track of when we are recording.
|
||||||
|
let recording = 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-----------------------------------------------
|
||||||
|
|
||||||
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const cmd = keyboardNameMap[e.keyCode];
|
||||||
|
|
||||||
|
// Start recording on space bar.
|
||||||
|
if (cmd == "SPACE" && !recording) {
|
||||||
|
|
||||||
|
post('update-recorder', {
|
||||||
|
isRecording: true,
|
||||||
|
uid: null
|
||||||
|
});
|
||||||
|
|
||||||
|
recording = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const onKeyUp = (e: KeyboardEvent) => {
|
||||||
|
const cmd = keyboardNameMap[e.keyCode];
|
||||||
|
|
||||||
|
// Stop recording on space up.
|
||||||
|
if (cmd == "SPACE" && recording) {
|
||||||
|
|
||||||
|
// Render audio immediately.
|
||||||
|
const uid = render("", "", "", "sf");
|
||||||
|
|
||||||
|
post('update-recorder', {
|
||||||
|
isRecording: false,
|
||||||
|
uid: uid
|
||||||
|
});
|
||||||
|
|
||||||
|
recording = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener("keydown", onKeyDown);
|
||||||
|
window.addEventListener("keyup", onKeyUp);
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
recording
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
173
src/components/inputItem/controllers/textCtrl.ts
Normal file
173
src/components/inputItem/controllers/textCtrl.ts
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
import anime from "animejs";
|
||||||
|
import useMitt from "@/modules/mitt";
|
||||||
|
import { useIpc } from '@/modules/ipc';
|
||||||
|
import { Ref, watch, onMounted } from "vue";
|
||||||
|
import keyboardNameMap from "../keyBoardMaps/keyboardNameMap";
|
||||||
|
import { clientMessage, renderMessage } from '@/modules/message';
|
||||||
|
|
||||||
|
// Post a message to the backend.
|
||||||
|
const { post } = useIpc();
|
||||||
|
|
||||||
|
|
||||||
|
//---Animations-----------------------------------------------
|
||||||
|
|
||||||
|
let side = "right"; // Side of parent we are on.
|
||||||
|
let visible = false; // Whether textInput is visible.
|
||||||
|
|
||||||
|
function showTextInput () {
|
||||||
|
let t1 = (side === "right") ? 50 : -70;
|
||||||
|
let t2 = (side === "right") ? 110 : -130;
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: '#textInput',
|
||||||
|
opacity: [0, 1],
|
||||||
|
translateX: [t1, t2],
|
||||||
|
scale: [0.3, 1],
|
||||||
|
duration: 500,
|
||||||
|
easing: 'easeOutExpo',
|
||||||
|
})
|
||||||
|
|
||||||
|
visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTextInput() {
|
||||||
|
let t = (side === "right") ? 50 : -80;
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: '#textInput',
|
||||||
|
opacity: 0,
|
||||||
|
translateX: t,
|
||||||
|
scale: 0.3,
|
||||||
|
duration: 500,
|
||||||
|
easing: 'easeOutExpo',
|
||||||
|
})
|
||||||
|
|
||||||
|
visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchSide(currentSide: string) {
|
||||||
|
let t = (currentSide === "right") ? -130 : 110;
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: '#textInput',
|
||||||
|
translateX: t,
|
||||||
|
duration: 500,
|
||||||
|
easing: 'easeOutExpo',
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
export default function useTextInputController(elementX: Ref) {
|
||||||
|
let textInput: HTMLInputElement | null;
|
||||||
|
|
||||||
|
let length: number;
|
||||||
|
|
||||||
|
// For sending messages.
|
||||||
|
const { post } = useIpc();
|
||||||
|
const { emitter } = useMitt();
|
||||||
|
|
||||||
|
// Keep track of first key press.
|
||||||
|
let firstKey = true;
|
||||||
|
|
||||||
|
// Clear text input.
|
||||||
|
const clearInput = () => {
|
||||||
|
if (textInput) textInput.value = "";
|
||||||
|
hideTextInput()
|
||||||
|
firstKey = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a message and clean up after.
|
||||||
|
const sendMessage = () => {
|
||||||
|
if (textInput) {
|
||||||
|
|
||||||
|
// Render message
|
||||||
|
const uid = render(textInput.value, false, "", "sf");
|
||||||
|
|
||||||
|
// Send it to the backend for processing.
|
||||||
|
const clientM = clientMessage(textInput.value, false, uid);
|
||||||
|
post('client-message', clientM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---Callbacks-----------------------------------------------
|
||||||
|
|
||||||
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
|
||||||
|
if (textInput) {
|
||||||
|
const key = keyboardNameMap[e.keyCode]
|
||||||
|
|
||||||
|
// Reveal textInput on first key press.
|
||||||
|
if (firstKey) {
|
||||||
|
|
||||||
|
// Handle for space bar
|
||||||
|
if (key == "SPACE") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showTextInput()
|
||||||
|
firstKey = false
|
||||||
|
}
|
||||||
|
|
||||||
|
textInput.focus();
|
||||||
|
|
||||||
|
if (textInput.value == "" && !firstKey) {
|
||||||
|
clearInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == "ENTER") {
|
||||||
|
if (textInput.value) {
|
||||||
|
sendMessage()
|
||||||
|
clearInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == "ESCAPE") {
|
||||||
|
clearInput()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
|
// Watch parent position and update side.
|
||||||
|
watch(elementX, (elementX, previous) => {
|
||||||
|
const winW = window.innerWidth
|
||||||
|
|
||||||
|
// Logic depends on the side we are on.
|
||||||
|
if (side === "right") {
|
||||||
|
if (winW - elementX < 230) {
|
||||||
|
switchSide(side)
|
||||||
|
side = "left"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (winW - elementX > 230) {
|
||||||
|
switchSide(side)
|
||||||
|
side = "right"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
textInput = document.getElementById("textInput") as HTMLInputElement;
|
||||||
|
window.addEventListener("keydown", onKeyDown);
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
* Main logic used by inputItem component.
|
|
||||||
* Will visualize text input by default as user types.
|
|
||||||
* If user holds space bar down, input audio stream will
|
|
||||||
* be recorded and sent to the backend for analysis.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ref, watch, onUnmounted, onMounted } from "vue";
|
|
||||||
import useMitt from "@/modules/mitt";
|
|
||||||
import { useIpc } from '@/modules/ipc';
|
|
||||||
import keyboardNameMap from "./keyBoardMaps/keyboardNameMap";
|
|
||||||
import keyboardCharMap from "./keyBoardMaps/keyboardCharMap";
|
|
||||||
import anime from "animejs";
|
|
||||||
import { clientMessage, renderMessage } from '@/modules/message';
|
|
||||||
|
|
||||||
let textInput: HTMLInputElement | null;
|
|
||||||
|
|
||||||
// Animation functions for text input element.
|
|
||||||
function expandInput() {
|
|
||||||
anime({
|
|
||||||
targets: textInput,
|
|
||||||
width: ['0px', '150px'],
|
|
||||||
duration: 500,
|
|
||||||
easing: 'easeOutExpo',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function retractInput() {
|
|
||||||
anime({
|
|
||||||
targets: textInput,
|
|
||||||
width: ['150px', '0px'],
|
|
||||||
duration: 500,
|
|
||||||
easing: 'easeOutExpo',
|
|
||||||
begin: function() {
|
|
||||||
if (textInput) textInput.blur();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function useInputController() {
|
|
||||||
|
|
||||||
const { emitter } = useMitt();
|
|
||||||
const { post } = useIpc();
|
|
||||||
const isRecording = ref(false);
|
|
||||||
const isTyping = ref(false);
|
|
||||||
const input = ref("");
|
|
||||||
const capsLock = 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);
|
|
||||||
console.log(m.time)
|
|
||||||
return m.uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send message on ENTER.
|
|
||||||
const onEnter = () => {
|
|
||||||
|
|
||||||
if (input.value) {
|
|
||||||
|
|
||||||
// Render the message immediately and get its unique id.
|
|
||||||
const uid = render(input.value, false, "", "sf");
|
|
||||||
|
|
||||||
// Then send it to the backend for processing.
|
|
||||||
const clientM = clientMessage(input.value, false, uid);
|
|
||||||
post('client-message', clientM);
|
|
||||||
|
|
||||||
// Reset the text input.
|
|
||||||
if (textInput) textInput.value = '';
|
|
||||||
input.value = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// update input on keydown event & listen for special commands.
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if (textInput) {
|
|
||||||
textInput.focus();
|
|
||||||
textInput.value = input.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyboardCharMap is an array of arrays, with each inner
|
|
||||||
// array having 2 columns - un-shifted, and shifted values.
|
|
||||||
// iCol = 0 is the un-shifted value, while iCol=1 is the shifted value.
|
|
||||||
// See the "keyboardCharMap" module for possible keys.
|
|
||||||
// MODIFY keyboardCharMap to suit your needs if you want
|
|
||||||
// more/less/different characters to be considered "printable".
|
|
||||||
let iCol = 0;
|
|
||||||
if (e.shiftKey || capsLock.value) {
|
|
||||||
iCol = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ch = keyboardCharMap[e.keyCode][iCol];
|
|
||||||
|
|
||||||
// Optionally do things with non-printables,
|
|
||||||
// like CR, ESC, Backspace, LF, Tab, Arrows, F1-F24, etc.
|
|
||||||
// See the arrary "keyboardNameMap" module for possible keys.
|
|
||||||
const cmd = keyboardNameMap[e.keyCode];
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case "ENTER":
|
|
||||||
onEnter();
|
|
||||||
break;
|
|
||||||
case "BACK_SPACE":
|
|
||||||
input.value = input.value.slice(0, -1);
|
|
||||||
break;
|
|
||||||
case "CAPS_LOCK":
|
|
||||||
capsLock.value = true;
|
|
||||||
break;
|
|
||||||
case "ESCAPE":
|
|
||||||
if (textInput) textInput.value = ''
|
|
||||||
input.value = "";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
input.value += ch;
|
|
||||||
input.value.trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop stream recording and render audio message on space key up event.
|
|
||||||
const onKeyUp = (e: KeyboardEvent) => {
|
|
||||||
if (e.key === " " && isRecording.value) {
|
|
||||||
|
|
||||||
isRecording.value = false;
|
|
||||||
|
|
||||||
// // Render the message immediately and get its unique id.
|
|
||||||
const uid = render("", "", "", "sf");
|
|
||||||
// Notify main process to stop recording and send send audio to backend for analysis.
|
|
||||||
post('update-recorder', {
|
|
||||||
isRecording: isRecording.value,
|
|
||||||
uid
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset input.
|
|
||||||
input.value = ''
|
|
||||||
}
|
|
||||||
else if (e.code === "CapsLock") {
|
|
||||||
capsLock.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
textInput = document.getElementById('textInput') as HTMLInputElement;
|
|
||||||
// add window event keyboard listeners
|
|
||||||
window.addEventListener("keydown", onKeyDown);
|
|
||||||
window.addEventListener('keyup', onKeyUp);
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener("keydown", onKeyDown);
|
|
||||||
window.removeEventListener("keyup", onKeyUp);
|
|
||||||
});
|
|
||||||
|
|
||||||
// watch keyboard input & update inputItem state.
|
|
||||||
watch(input, (input, prevInput) => {
|
|
||||||
if (isTyping.value && input.length === 0) {
|
|
||||||
retractInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing if user is typing.
|
|
||||||
if (prevInput !== "" || prevInput.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin stream recording on space bar.
|
|
||||||
if (input === " " && isRecording.value === false) {
|
|
||||||
isTyping.value = false;
|
|
||||||
isRecording.value = true;
|
|
||||||
// tell main process to begin stream recording.
|
|
||||||
post('update-recorder', {
|
|
||||||
isRecording: isRecording.value,
|
|
||||||
uid: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isTyping.value = true;
|
|
||||||
expandInput()
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
isRecording,
|
|
||||||
isTyping
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -2,22 +2,25 @@
|
||||||
<div
|
<div
|
||||||
id="inputItem"
|
id="inputItem"
|
||||||
class="input-item"
|
class="input-item"
|
||||||
:class="{ playing: isRecording }"
|
:class="{ playing: recording }"
|
||||||
:style="{ top: `${elementY}px`, left: `${elementX}px` }"
|
:style="{ top: `${elementY}px`, left: `${elementX}px` }"
|
||||||
>
|
>
|
||||||
AG
|
AG
|
||||||
|
|
||||||
<!-- animations for recording and on-standby -->
|
<!-- Show audio input on spacebar -->
|
||||||
<span v-if="isRecording" class="play"></span>
|
<AudioInput />
|
||||||
<span v-if="isRecording" class="pause">
|
|
||||||
|
|
||||||
|
<span v-if="recording" class="play"></span>
|
||||||
|
<span v-if="recording" class="pause">
|
||||||
<div class="rec-icon"></div>
|
<div class="rec-icon"></div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- Show text input on key-down -->
|
<!-- Show text input on key-down -->
|
||||||
<TextInput :position="elementX"/>
|
<TextInput />
|
||||||
|
|
||||||
<!-- Show suggestions menu on click -->
|
<!-- Show suggestions menu on click -->
|
||||||
<!-- <SuggestionsMenu /> -->
|
<!-- <Menu /> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -26,8 +29,12 @@
|
||||||
|
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import draggify from "@/modules/draggify";
|
import draggify from "@/modules/draggify";
|
||||||
import useInputController from "./inputController";
|
|
||||||
import TextInput from "@/components/inputItem/textInput.vue"
|
import TextInput from "@/components/inputItem/textInput.vue"
|
||||||
|
import useTextInputController from
|
||||||
|
"@/components/inputItem/controllers/textCtrl"
|
||||||
|
import useAudioInputController from
|
||||||
|
"@/components/inputItem/controllers/audioCtrl"
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "InputItem",
|
name: "InputItem",
|
||||||
|
|
@ -39,14 +46,14 @@ export default defineComponent({
|
||||||
// Calculate position of inputItem on drag.
|
// Calculate position of inputItem on drag.
|
||||||
const { elementX, elementY } = draggify({ elementId: "inputItem" });
|
const { elementX, elementY } = draggify({ elementId: "inputItem" });
|
||||||
|
|
||||||
// determine whether the user is typing or recording.
|
// Controllers for text and audio.
|
||||||
const { isRecording, isTyping } = useInputController();
|
useTextInputController(elementX)
|
||||||
|
const { recording } = useAudioInputController()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elementX,
|
elementX,
|
||||||
elementY,
|
elementY,
|
||||||
isRecording,
|
recording
|
||||||
isTyping,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -57,6 +64,8 @@ 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;
|
||||||
|
|
@ -66,12 +75,12 @@ export default defineComponent({
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
||||||
border: 4px solid #C6C6C6;
|
|
||||||
border-radius: 24px;
|
|
||||||
|
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
|
||||||
background-color: white;
|
// border: 4px solid #C6C6C6;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
<template>
|
|
||||||
<div id="menu">
|
|
||||||
<ul id="menu-list">
|
|
||||||
<li
|
|
||||||
v-for="suggestion in menuItems.values()"
|
|
||||||
@click="submitSuggestion(suggestion)"
|
|
||||||
>
|
|
||||||
{{ suggestion }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, ref } from "vue";
|
|
||||||
import useMenu from "./menuController";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "SuggestionsMenu",
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const menuItems = ref(new Map())
|
|
||||||
// menuItems.value.set(0, 'add contact')
|
|
||||||
// menuItems.value.set(1, 'delete contact')
|
|
||||||
// menuItems.value.set(2, 'show contacts')
|
|
||||||
// menuItems.value.set(3, 'send a message')
|
|
||||||
|
|
||||||
const { submitSuggestion } = useMenu();
|
|
||||||
|
|
||||||
return {
|
|
||||||
menuItems,
|
|
||||||
submitSuggestion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
#menu {
|
|
||||||
margin-top: 20px;
|
|
||||||
min-width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 18px;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
animation-name: menu-appear;
|
|
||||||
animation-duration: 1s;
|
|
||||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes menu-appear {
|
|
||||||
from {
|
|
||||||
height: 0px;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function useMenu() {
|
|
||||||
|
|
||||||
const submitSuggestion = (suggestion: string) => {
|
|
||||||
console.log(`Submit...${suggestion}`)
|
|
||||||
|
|
||||||
// // Render the message immediately and get its unique id.
|
|
||||||
// const uid = render(suggestion, false, "", "sf");
|
|
||||||
|
|
||||||
// // Then send it to the backend for processing.
|
|
||||||
// const clientM = clientMessage(suggestion, false, uid);
|
|
||||||
// post('client-message', clientM);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
submitSuggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div
|
<input
|
||||||
class="text-input"
|
id="textInput"
|
||||||
:class="`text-input-${updateSide}`"
|
type="text"
|
||||||
>
|
/>
|
||||||
<input id="textInput" type="text" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -15,54 +13,48 @@ import { defineComponent, ref, watch } from "vue";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "TextInput",
|
name: "TextInput",
|
||||||
|
|
||||||
data: {
|
|
||||||
|
|
||||||
// Where is avatar?
|
|
||||||
position: Number
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(data) {
|
|
||||||
|
|
||||||
const side = ref("")
|
|
||||||
side.value = "left"
|
|
||||||
|
|
||||||
// Watch the position of parent.
|
|
||||||
// watch(data.position, (position, prevPosition) => {
|
|
||||||
// console.log("position moved")
|
|
||||||
// })
|
|
||||||
|
|
||||||
return {
|
|
||||||
side
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
.text-input {
|
#textInput {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
height: 36px;
|
height: 16px;
|
||||||
|
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
|
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15);
|
||||||
}
|
|
||||||
|
|
||||||
// Activate if we need
|
transform: translateX(50px) scale(0.3);
|
||||||
.text-input-left {
|
|
||||||
|
|
||||||
left: -200px;
|
|
||||||
background-color: red;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes appear {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(50px) scale(0.3);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(110px) scale(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -113,8 +113,8 @@ export default function draggify(input: { elementId: string }) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the coordinants.
|
// Initialize the coordinants.
|
||||||
elementX.value = 20;
|
elementX.value = 15;
|
||||||
elementY.value = 200 - 38 - 20;
|
elementY.value = 300;
|
||||||
|
|
||||||
// remove event listeners on component dismount.
|
// remove event listeners on component dismount.
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue