Merge branch 'scroll_animate' into 'master'
Scroll animate See merge request crimata-ai/crimata-electron!3
This commit is contained in:
commit
b02243873c
21 changed files with 1038 additions and 299 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,7 +2,7 @@
|
|||
node_modules
|
||||
/dist
|
||||
/crate/target/*
|
||||
|
||||
/.log
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@
|
|||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@types/animejs": "^3.1.2",
|
||||
"@types/bindings": "^1.3.0",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@types/ws": "^7.2.7",
|
||||
"animejs": "^3.2.0",
|
||||
"core-js": "^3.6.5",
|
||||
"mitt": "^2.1.0",
|
||||
"speech-recorder": "^1.2.1",
|
||||
"vue": "^3.0.0-0",
|
||||
"vue-router": "^4.0.0-0",
|
||||
|
|
@ -27,7 +29,6 @@
|
|||
"ws": "^7.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/animejs": "^3.1.2",
|
||||
"@types/jest": "^24.0.19",
|
||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||
"@typescript-eslint/parser": "^2.33.0",
|
||||
|
|
|
|||
|
|
@ -8,26 +8,26 @@ import * as path from "path";
|
|||
import { SpeechRecorder } from "speech-recorder";
|
||||
import WebSocket from "ws";
|
||||
|
||||
const ws = new WebSocket("ws://localhost:8080");
|
||||
ws.on("open", function open() {
|
||||
ws.send("hello fro client");
|
||||
});
|
||||
ws.on("message", (message: any) => {
|
||||
console.log("received message", message);
|
||||
});
|
||||
|
||||
const recorder = new SpeechRecorder();
|
||||
|
||||
recorder.start({
|
||||
onAudio: (audio: object, speech: boolean) => {
|
||||
if (speech) {
|
||||
console.log(audio);
|
||||
ws.send(audio);
|
||||
}
|
||||
console.log("recording");
|
||||
// writeStream.write(audio);
|
||||
}
|
||||
});
|
||||
// const ws = new WebSocket("ws://localhost:8080");
|
||||
// ws.on("open", function open() {
|
||||
// ws.send("hello fro client");
|
||||
// });
|
||||
// ws.on("message", (message: any) => {
|
||||
// console.log("received message", message);
|
||||
// });
|
||||
//
|
||||
// const recorder = new SpeechRecorder();
|
||||
//
|
||||
// recorder.start({
|
||||
// onAudio: (audio: object, speech: boolean) => {
|
||||
// if (speech) {
|
||||
// console.log(audio);
|
||||
// ws.send(audio);
|
||||
// }
|
||||
// console.log("recording");
|
||||
// // writeStream.write(audio);
|
||||
// }
|
||||
// });
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
|
|
|
|||
48
src/components/UI/UIDetails/inputItem.vue
Normal file
48
src/components/UI/UIDetails/inputItem.vue
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<foreignObject x="10" y="10" width="100%" height="100%">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div contenteditable
|
||||
v-if="input.length > 0"
|
||||
>
|
||||
{{ input }}
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import useKeyDownHandler from "@/composables/keyDownHandler/useKeyDownHandler";
|
||||
import { defineComponent, onUnmounted } from "vue";
|
||||
export default defineComponent({
|
||||
name: "InputItem",
|
||||
setup() {
|
||||
const {keyDownHandler, input} = useKeyDownHandler();
|
||||
|
||||
// add window event listener
|
||||
window.addEventListener("keydown", keyDownHandler);
|
||||
// remove Event Listener on component unMount
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("keydown", keyDownHandler);
|
||||
});
|
||||
|
||||
return {
|
||||
input
|
||||
};
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div[contenteditable] {
|
||||
width: auto;
|
||||
max-width: 200px;
|
||||
display: table;
|
||||
padding: 7px 15px 7px 15px;
|
||||
border: 0;
|
||||
border-radius: 25px;
|
||||
color: #fff;
|
||||
background-color: #61b4f4;
|
||||
font-size: 14;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,8 +5,7 @@
|
|||
:transform = "startingOffset"
|
||||
>
|
||||
<rect
|
||||
ref="bubbleTag"
|
||||
id="#bubble"
|
||||
ref="messageRect"
|
||||
x="30"
|
||||
y="10"
|
||||
width="196"
|
||||
|
|
@ -17,20 +16,19 @@
|
|||
<text
|
||||
font-size="14"
|
||||
font-family="SF Pro"
|
||||
id="#message"
|
||||
ref="contentTag"
|
||||
ref="messageText"
|
||||
:fill="textFill"
|
||||
>
|
||||
<tspan
|
||||
dy="16"
|
||||
x="0"
|
||||
v-for="(item, index) in textArr"
|
||||
:key="index"
|
||||
dy="16"
|
||||
x="0"
|
||||
v-for="(item, index) in textArr"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</tspan>
|
||||
</text>
|
||||
<g :transform="signature">
|
||||
<g :transform="signatureTranslate">
|
||||
<image
|
||||
xlink:href="profile.png"
|
||||
width="29"
|
||||
|
|
@ -54,8 +52,11 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, onMounted, ref, reactive } from 'vue';
|
||||
export default defineComponent({
|
||||
import { defineComponent, onMounted, ref, reactive } from 'vue';
|
||||
import useMessageItemComp from "@/composables/computed/useMessageItemComp";
|
||||
import useMessageItemAnims from "@/composables/anims/useMessageItemAnims";
|
||||
import useTextWrap from "@/composables/textWrap/useTextWrap";
|
||||
export default defineComponent({
|
||||
name: "MessageItem",
|
||||
props: {
|
||||
item: {
|
||||
|
|
@ -64,99 +65,38 @@ import { defineComponent, computed, onMounted, ref, reactive } from 'vue';
|
|||
},
|
||||
},
|
||||
setup(props) {
|
||||
let textArr: string[] = reactive([]);
|
||||
|
||||
let textArr: string[] = reactive([]);
|
||||
const signature = ref("");
|
||||
const msgID = ref(props.item.id);
|
||||
const bubbleTag = ref(`bubble${msgID.value}`);
|
||||
const contentTag = ref(`content${msgID.value}`);
|
||||
let bubble: any;
|
||||
let content: any;
|
||||
const msgID = ref(props.item.id);
|
||||
const messageRect = ref(`message${msgID.value}`);
|
||||
const messageText = ref(`text${msgID.value}`);
|
||||
|
||||
const textFill = computed(() => {
|
||||
switch (props.item.modifier) {
|
||||
case "ai":
|
||||
return "#fff";
|
||||
default:
|
||||
return "#000";
|
||||
}
|
||||
});
|
||||
const { textFill, bubbleFill, startingOffset } = useMessageItemComp(props.item.modifier);
|
||||
const { textWrap } = useTextWrap();
|
||||
const { drawMessage, signatureTranslate } = useMessageItemAnims({
|
||||
mr: messageRect,
|
||||
tr: messageText,
|
||||
})
|
||||
|
||||
const bubbleFill = computed(() => {
|
||||
switch (props.item.modifier) {
|
||||
case "sf":
|
||||
return "#61b4f4";
|
||||
case "ai":
|
||||
return "#585858";
|
||||
default:
|
||||
return "#fff";
|
||||
}
|
||||
});
|
||||
// wraps message text before render
|
||||
textArr = textWrap({
|
||||
s: props.item.content,
|
||||
w: 32
|
||||
});
|
||||
|
||||
const startingOffset = computed(() => {
|
||||
switch (props.item.modifier) {
|
||||
case "sf":
|
||||
return "translate(10, 600)";
|
||||
case "ai":
|
||||
return "translate(135, 600)";
|
||||
default:
|
||||
return "translate(20, 600)";
|
||||
}
|
||||
})
|
||||
|
||||
function signaturePosition(): void {
|
||||
if (bubble.getAttribute("height") !== null) {
|
||||
const height = Number(bubble.getAttribute("height"));
|
||||
const p = -10;
|
||||
signature.value = `translate(-10 ${height + p})`;
|
||||
}
|
||||
}
|
||||
|
||||
function createTextBox(s: string, w: number): void {
|
||||
// return tspan elements for text with correct size
|
||||
const wrap = (s: string, w: number) =>
|
||||
s.replace(
|
||||
new RegExp(`(?![^\\n]{1,${w}}$)([^\\n]{1,${w}})\\s`, "g"),
|
||||
"$1\n"
|
||||
);
|
||||
textArr = wrap(s, w).split("\n");
|
||||
}
|
||||
|
||||
function adjustRect(): void {
|
||||
// must get dimensions of text box to fit bubble around
|
||||
const padding = 20;
|
||||
const bbox = content.getBBox();
|
||||
bubble.setAttribute("x", bbox.x - padding);
|
||||
bubble.setAttribute("y", bbox.y - padding);
|
||||
bubble.setAttribute("width", bbox.width + 2 * padding);
|
||||
bubble.setAttribute("height", bbox.height + 2 * padding);
|
||||
}
|
||||
|
||||
// make textbox before mount
|
||||
createTextBox(props.item.content, 32);
|
||||
|
||||
onMounted(async () => {
|
||||
// update bubble and content for current message
|
||||
bubble = bubbleTag.value;
|
||||
content = contentTag.value;
|
||||
await adjustRect();
|
||||
signaturePosition();
|
||||
|
||||
})
|
||||
return {
|
||||
textFill,
|
||||
bubbleFill,
|
||||
startingOffset,
|
||||
signaturePosition,
|
||||
textArr,
|
||||
signature,
|
||||
contentTag,
|
||||
msgID,
|
||||
bubbleTag
|
||||
}
|
||||
onMounted(() => {
|
||||
drawMessage();
|
||||
})
|
||||
|
||||
return {
|
||||
textFill,
|
||||
bubbleFill,
|
||||
startingOffset,
|
||||
textArr,
|
||||
signatureTranslate,
|
||||
messageText,
|
||||
messageRect
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
interface Message {
|
||||
content: string;
|
||||
signature: string;
|
||||
outgoing: boolean;
|
||||
modifier: string;
|
||||
imgURL: string;
|
||||
id: string;
|
||||
}
|
||||
import { Message } from "@/types/message/index";
|
||||
|
||||
const Messages: Message[] = [
|
||||
{
|
||||
content:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
@click="renderMessage"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
|
|
@ -37,24 +38,24 @@
|
|||
</clipPath>
|
||||
</defs>
|
||||
<g id="cardsDiv">
|
||||
<g
|
||||
v-for="(item, index) in renderArr"
|
||||
:key="index"
|
||||
id="cards"
|
||||
transform="translate(0, 0)"
|
||||
<g
|
||||
v-for="(item, index) in renderArr"
|
||||
:key="index"
|
||||
:id="index"
|
||||
class="test"
|
||||
transform="translate(0, 0)"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
v-on:appear-cancelled="leave"
|
||||
>
|
||||
<MessageItem
|
||||
:item="item"
|
||||
:key="index"
|
||||
/>
|
||||
</transition>
|
||||
</g>
|
||||
<MessageItem
|
||||
:item="item"
|
||||
:key="index"
|
||||
/>
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
<g id="titlebar" transform="translate(0, 0)">
|
||||
<g data-name="Group 73" transform="translate(20 20)">
|
||||
|
|
@ -83,118 +84,37 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject, onMounted, reactive } from "vue";
|
||||
import MessageItem from './UIDetails/messageItem.vue';
|
||||
import Messages from "./UIDetails/messages";
|
||||
export default defineComponent({
|
||||
name: 'UIindex',
|
||||
components: { MessageItem },
|
||||
setup() {
|
||||
import { defineComponent, ref, reactive } from "vue";
|
||||
import MessageItem from './UIDetails/messageItem.vue';
|
||||
import InputItem from "./UIDetails/inputItem.vue";
|
||||
import Messages from "./UIDetails/messages";
|
||||
import useUIindexAnims from "@/composables/anims/useUIindexAnims";
|
||||
export default defineComponent({
|
||||
name: 'UIindex',
|
||||
components: { MessageItem },
|
||||
setup() {
|
||||
const renderArr: Message[] = reactive([])
|
||||
const messages = Messages;
|
||||
const count = ref(0);
|
||||
|
||||
interface ProtectedRef {
|
||||
readonly el: SVGElement | HTMLElement;
|
||||
reference: any;
|
||||
height: number | null;
|
||||
}
|
||||
const anime: object | any = inject('animejs');
|
||||
const timeline: typeof anime = anime.timeline({ loop: true });
|
||||
const renderArr: Message[] = reactive([])
|
||||
const messages = Messages;
|
||||
const msgOffset = {
|
||||
x: 0 ,
|
||||
y: 0
|
||||
}
|
||||
let messenger: any;
|
||||
let winW: number;
|
||||
let modifier: string;
|
||||
let msg: any;
|
||||
let cardsDiv: any;
|
||||
let prevCardH = 0;
|
||||
const { beforeEnter, enter } = useUIindexAnims();
|
||||
|
||||
function renderMsg(i: number): void {
|
||||
setTimeout(() => {
|
||||
renderArr.push(messages[i]);
|
||||
}, 2000);
|
||||
}
|
||||
const renderMessage = () => {
|
||||
if (count.value < messages.length) {
|
||||
renderArr.push(messages[count.value])
|
||||
count.value++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function runAnim(): void {
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
renderMsg(i);
|
||||
}
|
||||
}
|
||||
|
||||
async function beforeEnter(el: any) {
|
||||
modifier = el.className.baseVal.substring(0, 2);
|
||||
}
|
||||
|
||||
async function enter(el: any, done: any) {
|
||||
const paddingLeft = 40;
|
||||
msg = await document.getElementById(el.id);
|
||||
const rect = msg.getBoundingClientRect();
|
||||
const msgW = rect.width;
|
||||
const msgH = rect.height;
|
||||
cardsDiv = await document.getElementById("cardsDiv");
|
||||
const cdBox = cardsDiv.getBBox();
|
||||
|
||||
if (prevCardH === 0) {
|
||||
msgOffset.y += cdBox.height;
|
||||
} else if (prevCardH > msgH) {
|
||||
// cardsDiv is offset by 17.5
|
||||
msgOffset.y += prevCardH + msgH / 2 + 17.5;
|
||||
} else {
|
||||
msgOffset.y += cdBox.height - 20;
|
||||
}
|
||||
prevCardH = msgH;
|
||||
|
||||
switch (modifier) {
|
||||
case "sf":
|
||||
msgOffset.x = winW - msgW;
|
||||
break;
|
||||
case "ai":
|
||||
msgOffset.x = (winW - msgW) / 2;
|
||||
break;
|
||||
default:
|
||||
msgOffset.x = paddingLeft;
|
||||
}
|
||||
|
||||
const translateUp = `translate(${msgOffset.x} ${msgOffset.y})`;
|
||||
const translateDown = `translate(${msgOffset.x} ${msgOffset.y + 5})`;
|
||||
timeline
|
||||
.add({
|
||||
targets: el,
|
||||
transform: translateUp,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 1000
|
||||
})
|
||||
.add({
|
||||
targets: el,
|
||||
transform: translateDown,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
offset: 1000
|
||||
});
|
||||
done();
|
||||
}
|
||||
|
||||
function leave() {
|
||||
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
messenger = document.getElementById('messenger');
|
||||
winW = messenger.clientWidth;
|
||||
runAnim();
|
||||
});
|
||||
return {
|
||||
// timeline,
|
||||
renderArr,
|
||||
msgOffset,
|
||||
beforeEnter,
|
||||
enter,
|
||||
leave
|
||||
}
|
||||
},
|
||||
});
|
||||
return {
|
||||
renderMessage,
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
49
src/composables/anims/useMessageItemAnims.ts
Normal file
49
src/composables/anims/useMessageItemAnims.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { ref, onMounted } from "vue";
|
||||
interface Ref<A> {
|
||||
value: A;
|
||||
}
|
||||
export default function useMessageItemAnims({
|
||||
mr,
|
||||
tr,
|
||||
}: {
|
||||
mr: Ref<string>;
|
||||
tr: Ref<string>;
|
||||
}) {
|
||||
const signatureTranslate = ref("");
|
||||
let messageRect: SVGSVGElement & SVGRectElement;
|
||||
let messageText: SVGSVGElement & SVGTextElement;
|
||||
|
||||
onMounted(async () => {
|
||||
messageRect = (mr.value as unknown) as SVGSVGElement & SVGRectElement;
|
||||
messageText = (tr.value as unknown) as SVGSVGElement & SVGTextElement;
|
||||
});
|
||||
|
||||
function adjustMessageRect(): void {
|
||||
// must get dimensions of text box to fit bubble around
|
||||
const padding = 20;
|
||||
const textBox = messageText.getBBox();
|
||||
messageRect.setAttribute("x", String(textBox.x - padding));
|
||||
messageRect.setAttribute("y", String(textBox.y - padding));
|
||||
messageRect.setAttribute("width", String(textBox.width + 2 * padding));
|
||||
messageRect.setAttribute("height", String(textBox.height + 2 * padding));
|
||||
}
|
||||
|
||||
function translateMsgSignature(): void {
|
||||
if (messageRect.getAttribute("height") !== null) {
|
||||
const height = Number(messageRect.getAttribute("height"));
|
||||
const p = -10;
|
||||
signatureTranslate.value = `translate(-10 ${height + p})`;
|
||||
}
|
||||
}
|
||||
|
||||
async function drawMessage() {
|
||||
// ignore lint error: await needed for proper render
|
||||
await adjustMessageRect();
|
||||
translateMsgSignature();
|
||||
}
|
||||
|
||||
return {
|
||||
drawMessage,
|
||||
signatureTranslate,
|
||||
};
|
||||
}
|
||||
148
src/composables/anims/useUIindexAnims.ts
Normal file
148
src/composables/anims/useUIindexAnims.ts
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import { inject, onMounted } from "vue";
|
||||
import AnimeFunc from "@/types/animejs/index";
|
||||
import { MessageAnimeFunc } from '@/types/message/index';
|
||||
export default function useUIindexAnims() {
|
||||
|
||||
// imports animejs safely
|
||||
let anime: AnimeFunc;
|
||||
const animeInject: AnimeFunc | undefined = inject("animejs");
|
||||
if (animeInject) anime = animeInject;
|
||||
|
||||
const msgOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
let winW: number;
|
||||
let modifier: string;
|
||||
let msg: HTMLElement | null;
|
||||
let prevCardH = 0;
|
||||
let totalHeight = 0;
|
||||
let messenger: HTMLElement | null;
|
||||
let renderList: NodeList;
|
||||
let scrollAnim = false;
|
||||
let scroll = 0;
|
||||
|
||||
onMounted(() => {
|
||||
messenger = document.getElementById("messenger");
|
||||
if (messenger) winW = messenger.clientWidth;
|
||||
});
|
||||
|
||||
function calculateAllMessageHeight(): void {
|
||||
const messages = document.querySelectorAll(".test");
|
||||
if (messages.length) {
|
||||
renderList = messages;
|
||||
for (const message of messages) {
|
||||
const el = message as SVGGElement;
|
||||
totalHeight += el.getBBox().height;
|
||||
}
|
||||
scrollAnim = totalHeight > 500 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
function beforeEnter(el: SVGGElement): void {
|
||||
modifier = el.className.baseVal.substring(0, 2);
|
||||
if (!scrollAnim) calculateAllMessageHeight();
|
||||
}
|
||||
|
||||
function scrollOffset(l: NodeList, height: number): void {
|
||||
for (const card of l) {
|
||||
const c = card.parentNode as HTMLElement;
|
||||
anime({
|
||||
targets: c,
|
||||
transform: `translate(0 ${height})`,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const scrollAnimate: MessageAnimeFunc = (el, transform) => {
|
||||
anime({
|
||||
targets: el, transform: transform.initialTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
begin: function() {
|
||||
scrollOffset(renderList, scroll);
|
||||
},
|
||||
complete: function() {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.finalTranslate,
|
||||
offset: 1000
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const stackAnimate: MessageAnimeFunc = (el, transform) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.initialTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 1000,
|
||||
complete: function() {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.finalTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
offset: 1000
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addMessage(el: SVGGElement): void {
|
||||
const transform = {
|
||||
initialTranslate: `translate(${msgOffset.x} ${msgOffset.y})`,
|
||||
finalTranslate: `translate(${msgOffset.x} ${msgOffset.y + 5})`
|
||||
}
|
||||
scrollAnim ? scrollAnimate(el, transform) : stackAnimate(el, transform)
|
||||
}
|
||||
|
||||
function setXoffset(messageWidth: number): void {
|
||||
const paddingLeft = 40;
|
||||
switch (modifier) {
|
||||
case "sf":
|
||||
msgOffset.x = winW - messageWidth;
|
||||
break;
|
||||
case "ai":
|
||||
msgOffset.x = (winW - messageWidth) / 2;
|
||||
break;
|
||||
default:
|
||||
msgOffset.x = paddingLeft;
|
||||
}
|
||||
}
|
||||
|
||||
function setYoffset(messageHeight: number): void {
|
||||
if (prevCardH === 0) {
|
||||
msgOffset.y += messageHeight;
|
||||
} else {
|
||||
msgOffset.y += prevCardH + messageHeight / 2 + 17.5;
|
||||
}
|
||||
prevCardH = messageHeight;
|
||||
}
|
||||
|
||||
function calculateMessageOffsets(msg: HTMLElement): void {
|
||||
const msgRect = msg.getBoundingClientRect();
|
||||
if (scrollAnim) {
|
||||
// update scroll
|
||||
scroll -= msgRect.height + msgRect.height / 2;
|
||||
}
|
||||
setXoffset(msgRect.width)
|
||||
setYoffset(msgRect.height)
|
||||
}
|
||||
|
||||
async function enter(el: SVGGElement): Promise<void> {
|
||||
msg = await document.getElementById(el.id);
|
||||
if (msg) calculateMessageOffsets(msg);
|
||||
addMessage(el);
|
||||
}
|
||||
|
||||
return {
|
||||
beforeEnter,
|
||||
enter,
|
||||
msgOffset,
|
||||
addMessage
|
||||
};
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
import { computed } from "vue";
|
||||
|
||||
export default function useMessageItemComp(modifier: string): string {
|
||||
// takes in message modifier as param
|
||||
export default function useMessageItemComp(m: string) {
|
||||
const textFill = computed(() => {
|
||||
switch (modifier) {
|
||||
case "ai":
|
||||
return "#fff";
|
||||
default:
|
||||
switch (m) {
|
||||
case "fr":
|
||||
return "#000";
|
||||
default:
|
||||
return "#fff";
|
||||
}
|
||||
});
|
||||
|
||||
const bubbleFill = computed(() => {
|
||||
switch (modifier) {
|
||||
switch (m) {
|
||||
case "sf":
|
||||
return "#61b4f4";
|
||||
case "ai":
|
||||
|
|
@ -22,15 +22,16 @@ export default function useMessageItemComp(modifier: string): string {
|
|||
});
|
||||
|
||||
const startingOffset = computed(() => {
|
||||
switch (modifier) {
|
||||
switch (m) {
|
||||
case "sf":
|
||||
return "translate(10, 600)";
|
||||
return "translate(115, 600)";
|
||||
case "ai":
|
||||
return "translate(135, 600)";
|
||||
return "translate(200, 600)";
|
||||
default:
|
||||
return "translate(20, 600)";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
textFill,
|
||||
bubbleFill,
|
||||
263
src/composables/keyDownHandler/keyboardMaps/keyboardCharMap.ts
Normal file
263
src/composables/keyDownHandler/keyboardMaps/keyboardCharMap.ts
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
// This has the UnShifted and Shifted characters that each key maps to
|
||||
// Ones that are to be ignored for character input are empty.
|
||||
const keyboardCharMap = [
|
||||
["", ""], // [0]
|
||||
["", ""], // [1]
|
||||
["", ""], // [2]
|
||||
["", ""], // [3]
|
||||
["", ""], // [4]
|
||||
["", ""], // [5]
|
||||
["", ""], // [6]
|
||||
["", ""], // [7]
|
||||
["", ""], // [8]
|
||||
["", ""], // [9]
|
||||
["", ""], // [10]
|
||||
["", ""], // [11]
|
||||
["", ""], // [12]
|
||||
["\r", "\r"], // [13] - MOST control characters are ignored. This one (Carriage Return, or "Enter") is significant!
|
||||
["", ""], // [14]
|
||||
["", ""], // [15]
|
||||
["", ""], // [16]
|
||||
["", ""], // [17]
|
||||
["", ""], // [18]
|
||||
["", ""], // [19]
|
||||
["", ""], // [20]
|
||||
["", ""], // [21]
|
||||
["", ""], // [22]
|
||||
["", ""], // [23]
|
||||
["", ""], // [24]
|
||||
["", ""], // [25]
|
||||
["", ""], // [26]
|
||||
["", ""], // [27]
|
||||
["", ""], // [28]
|
||||
["", ""], // [29]
|
||||
["", ""], // [30]
|
||||
["", ""], // [31]
|
||||
[" ", " "], // [32] // SPACE! Don't "clean it up" and remove the space!
|
||||
["", ""], // [33]
|
||||
["", ""], // [34]
|
||||
["", ""], // [35]
|
||||
["", ""], // [36]
|
||||
["", ""], // [37]
|
||||
["", ""], // [38]
|
||||
["", ""], // [39]
|
||||
["", ""], // [40]
|
||||
["", ""], // [41]
|
||||
["", ""], // [42]
|
||||
["", ""], // [43]
|
||||
["", ""], // [44]
|
||||
["", ""], // [45]
|
||||
["", ""], // [46]
|
||||
["", ""], // [47]
|
||||
["0", ")"], // [48]
|
||||
["1", "!"], // [49]
|
||||
["2", "@"], // [50]
|
||||
["3", "#"], // [51]
|
||||
["4", "$"], // [52]
|
||||
["5", "%"], // [53]
|
||||
["6", "^"], // [54]
|
||||
["7", "&"], // [55]
|
||||
["8", "*"], // [56]
|
||||
["9", "("], // [57]
|
||||
["", ""], // [58]
|
||||
[";", ":"], // [59]
|
||||
["<", ""], // [60]
|
||||
["=", ""], // [61]
|
||||
[">", ""], // [62]
|
||||
["?", ""], // [63] shifted; else "/"
|
||||
["", ""], // [64]
|
||||
["a", "A"], // [65]
|
||||
["b", "B"], // [66]
|
||||
["c", "C"], // [67]
|
||||
["d", "D"], // [68]
|
||||
["e", "E"], // [69]
|
||||
["f", "F"], // [70]
|
||||
["g", "G"], // [71]
|
||||
["h", "H"], // [72]
|
||||
["i", "I"], // [73]
|
||||
["j", "J"], // [74]
|
||||
["k", "K"], // [75]
|
||||
["l", "L"], // [76]
|
||||
["m", "M"], // [77]
|
||||
["n", "N"], // [78]
|
||||
["o", "O"], // [79]
|
||||
["p", "P"], // [80]
|
||||
["q", "Q"], // [81]
|
||||
["r", "R"], // [82]
|
||||
["s", "S"], // [83]
|
||||
["t", "T"], // [84]
|
||||
["u", "U"], // [85]
|
||||
["v", "V"], // [86]
|
||||
["w", "W"], // [87]
|
||||
["x", "X"], // [88]
|
||||
["y", "Y"], // [89]
|
||||
["z", "Z"], // [90]
|
||||
["", ""], // [91] Windows Key (Windows) or Command Key (Mac)
|
||||
["", ""], // [92]
|
||||
["", ""], // [93]
|
||||
["", ""], // [94]
|
||||
["", ""], // [95]
|
||||
// Number Keypad Entries...
|
||||
["0", ""], // [96]
|
||||
["1", ""], // [97]
|
||||
["2", ""], // [98]
|
||||
["3", ""], // [99]
|
||||
["4", ""], // [100]
|
||||
["5", ""], // [101]
|
||||
["6", ""], // [102]
|
||||
["7", ""], // [103]
|
||||
["8", ""], // [104]
|
||||
["9", ""], // [105]
|
||||
["*", ""], // [106]
|
||||
["+", ""], // [107]
|
||||
["", ""], // [108]
|
||||
["-", ""], // [109]
|
||||
[".", ""], // [110]
|
||||
["/", ""], // [111]
|
||||
|
||||
["", ""], // [112]
|
||||
["", ""], // [113]
|
||||
["", ""], // [114]
|
||||
["", ""], // [115]
|
||||
["", ""], // [116]
|
||||
["", ""], // [117]
|
||||
["", ""], // [118]
|
||||
["", ""], // [119]
|
||||
["", ""], // [120]
|
||||
["", ""], // [121]
|
||||
["", ""], // [122]
|
||||
["", ""], // [123]
|
||||
["", ""], // [124]
|
||||
["", ""], // [125]
|
||||
["", ""], // [126]
|
||||
["", ""], // [127]
|
||||
["", ""], // [128]
|
||||
["", ""], // [129]
|
||||
["", ""], // [130]
|
||||
["", ""], // [131]
|
||||
["", ""], // [132]
|
||||
["", ""], // [133]
|
||||
["", ""], // [134]
|
||||
["", ""], // [135]
|
||||
["", ""], // [136]
|
||||
["", ""], // [137]
|
||||
["", ""], // [138]
|
||||
["", ""], // [139]
|
||||
["", ""], // [140]
|
||||
["", ""], // [141]
|
||||
["", ""], // [142]
|
||||
["", ""], // [143]
|
||||
["", ""], // [144]
|
||||
["", ""], // [145]
|
||||
["", ""], // [146]
|
||||
["", ""], // [147]
|
||||
["", ""], // [148]
|
||||
["", ""], // [149]
|
||||
["", ""], // [150]
|
||||
["", ""], // [151]
|
||||
["", ""], // [152]
|
||||
["", ""], // [153]
|
||||
["", ""], // [154]
|
||||
["", ""], // [155]
|
||||
["", ""], // [156]
|
||||
["", ""], // [157]
|
||||
["", ""], // [158]
|
||||
["", ""], // [159]
|
||||
["", ""], // [160]
|
||||
["", ""], // [161]
|
||||
["", ""], // [162]
|
||||
["", ""], // [163]
|
||||
["", ""], // [164]
|
||||
["", ""], // [165]
|
||||
["", ""], // [166]
|
||||
["", ""], // [167]
|
||||
["", ""], // [168]
|
||||
["", ""], // [169]
|
||||
["", ""], // [170]
|
||||
["", ""], // [171]
|
||||
["", ""], // [172]
|
||||
["", ""], // [173]
|
||||
["", ""], // [174]
|
||||
["", ""], // [175]
|
||||
["", ""], // [176]
|
||||
["", ""], // [177]
|
||||
["", ""], // [178]
|
||||
["", ""], // [179]
|
||||
["", ""], // [180]
|
||||
["", ""], // [181]
|
||||
["", ""], // [182]
|
||||
["", ""], // [183]
|
||||
["", ""], // [184]
|
||||
["", ""], // [185]
|
||||
[";", ":"], // [186]
|
||||
["=", "+"], // [187]
|
||||
[",", "<"], // [188]
|
||||
["-", "_"], // [189]
|
||||
[".", ">"], // [190]
|
||||
["/", "?"], // [191]
|
||||
["`", "~"], // [192]
|
||||
["", ""], // [193]
|
||||
["", ""], // [194]
|
||||
["", ""], // [195]
|
||||
["", ""], // [196]
|
||||
["", ""], // [197]
|
||||
["", ""], // [198]
|
||||
["", ""], // [199]
|
||||
["", ""], // [200]
|
||||
["", ""], // [201]
|
||||
["", ""], // [202]
|
||||
["", ""], // [203]
|
||||
["", ""], // [204]
|
||||
["", ""], // [205]
|
||||
["", ""], // [206]
|
||||
["", ""], // [207]
|
||||
["", ""], // [208]
|
||||
["", ""], // [209]
|
||||
["", ""], // [210]
|
||||
["", ""], // [211]
|
||||
["", ""], // [212]
|
||||
["", ""], // [213]
|
||||
["", ""], // [214]
|
||||
["", ""], // [215]
|
||||
["", ""], // [216]
|
||||
["", ""], // [217]
|
||||
["", ""], // [218]
|
||||
["[", "{"], // [219]
|
||||
["\\", "|"], // [220]
|
||||
["]", "}"], // [221]
|
||||
["'", '"'], // [222]
|
||||
["", ""], // [223]
|
||||
["", ""], // [224]
|
||||
["", ""], // [225]
|
||||
["", ""], // [226]
|
||||
["", ""], // [227]
|
||||
["", ""], // [228]
|
||||
["", ""], // [229]
|
||||
["", ""], // [230]
|
||||
["", ""], // [231]
|
||||
["", ""], // [232]
|
||||
["", ""], // [233]
|
||||
["", ""], // [234]
|
||||
["", ""], // [235]
|
||||
["", ""], // [236]
|
||||
["", ""], // [237]
|
||||
["", ""], // [238]
|
||||
["", ""], // [239]
|
||||
["", ""], // [240]
|
||||
["", ""], // [241]
|
||||
["", ""], // [242]
|
||||
["", ""], // [243]
|
||||
["", ""], // [244]
|
||||
["", ""], // [245]
|
||||
["", ""], // [246]
|
||||
["", ""], // [247]
|
||||
["", ""], // [248]
|
||||
["", ""], // [249]
|
||||
["", ""], // [250]
|
||||
["", ""], // [251]
|
||||
["", ""], // [252]
|
||||
["", ""], // [253]
|
||||
["", ""], // [254]
|
||||
["", ""] // [255]
|
||||
];
|
||||
export default keyboardCharMap;
|
||||
261
src/composables/keyDownHandler/keyboardMaps/keyboardNameMap.ts
Normal file
261
src/composables/keyDownHandler/keyboardMaps/keyboardNameMap.ts
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
// names of known key codes (0-255)
|
||||
const keyboardNameMap = [
|
||||
"", // [0]
|
||||
"", // [1]
|
||||
"", // [2]
|
||||
"CANCEL", // [3]
|
||||
"", // [4]
|
||||
"", // [5]
|
||||
"HELP", // [6]
|
||||
"", // [7]
|
||||
"BACK_SPACE", // [8]
|
||||
"TAB", // [9]
|
||||
"", // [10]
|
||||
"", // [11]
|
||||
"CLEAR", // [12]
|
||||
"ENTER", // [13]
|
||||
"ENTER_SPECIAL", // [14]
|
||||
"", // [15]
|
||||
"SHIFT", // [16]
|
||||
"CONTROL", // [17]
|
||||
"ALT", // [18]
|
||||
"PAUSE", // [19]
|
||||
"CAPS_LOCK", // [20]
|
||||
"KANA", // [21]
|
||||
"EISU", // [22]
|
||||
"JUNJA", // [23]
|
||||
"FINAL", // [24]
|
||||
"HANJA", // [25]
|
||||
"", // [26]
|
||||
"ESCAPE", // [27]
|
||||
"CONVERT", // [28]
|
||||
"NONCONVERT", // [29]
|
||||
"ACCEPT", // [30]
|
||||
"MODECHANGE", // [31]
|
||||
"SPACE", // [32]
|
||||
"PAGE_UP", // [33]
|
||||
"PAGE_DOWN", // [34]
|
||||
"END", // [35]
|
||||
"HOME", // [36]
|
||||
"LEFT", // [37]
|
||||
"UP", // [38]
|
||||
"RIGHT", // [39]
|
||||
"DOWN", // [40]
|
||||
"SELECT", // [41]
|
||||
"PRINT", // [42]
|
||||
"EXECUTE", // [43]
|
||||
"PRINTSCREEN", // [44]
|
||||
"INSERT", // [45]
|
||||
"DELETE", // [46]
|
||||
"", // [47]
|
||||
"0", // [48]
|
||||
"1", // [49]
|
||||
"2", // [50]
|
||||
"3", // [51]
|
||||
"4", // [52]
|
||||
"5", // [53]
|
||||
"6", // [54]
|
||||
"7", // [55]
|
||||
"8", // [56]
|
||||
"9", // [57]
|
||||
"COLON", // [58]
|
||||
"SEMICOLON", // [59]
|
||||
"LESS_THAN", // [60]
|
||||
"EQUALS", // [61]
|
||||
"GREATER_THAN", // [62]
|
||||
"QUESTION_MARK", // [63]
|
||||
"AT", // [64]
|
||||
"A", // [65]
|
||||
"B", // [66]
|
||||
"C", // [67]
|
||||
"D", // [68]
|
||||
"E", // [69]
|
||||
"F", // [70]
|
||||
"G", // [71]
|
||||
"H", // [72]
|
||||
"I", // [73]
|
||||
"J", // [74]
|
||||
"K", // [75]
|
||||
"L", // [76]
|
||||
"M", // [77]
|
||||
"N", // [78]
|
||||
"O", // [79]
|
||||
"P", // [80]
|
||||
"Q", // [81]
|
||||
"R", // [82]
|
||||
"S", // [83]
|
||||
"T", // [84]
|
||||
"U", // [85]
|
||||
"V", // [86]
|
||||
"W", // [87]
|
||||
"X", // [88]
|
||||
"Y", // [89]
|
||||
"Z", // [90]
|
||||
"OS_KEY", // [91] Windows Key (Windows) or Command Key (Mac)
|
||||
"", // [92]
|
||||
"CONTEXT_MENU", // [93]
|
||||
"", // [94]
|
||||
"SLEEP", // [95]
|
||||
"NUMPAD0", // [96]
|
||||
"NUMPAD1", // [97]
|
||||
"NUMPAD2", // [98]
|
||||
"NUMPAD3", // [99]
|
||||
"NUMPAD4", // [100]
|
||||
"NUMPAD5", // [101]
|
||||
"NUMPAD6", // [102]
|
||||
"NUMPAD7", // [103]
|
||||
"NUMPAD8", // [104]
|
||||
"NUMPAD9", // [105]
|
||||
"MULTIPLY", // [106]
|
||||
"ADD", // [107]
|
||||
"SEPARATOR", // [108]
|
||||
"SUBTRACT", // [109]
|
||||
"DECIMAL", // [110]
|
||||
"DIVIDE", // [111]
|
||||
"F1", // [112]
|
||||
"F2", // [113]
|
||||
"F3", // [114]
|
||||
"F4", // [115]
|
||||
"F5", // [116]
|
||||
"F6", // [117]
|
||||
"F7", // [118]
|
||||
"F8", // [119]
|
||||
"F9", // [120]
|
||||
"F10", // [121]
|
||||
"F11", // [122]
|
||||
"F12", // [123]
|
||||
"F13", // [124]
|
||||
"F14", // [125]
|
||||
"F15", // [126]
|
||||
"F16", // [127]
|
||||
"F17", // [128]
|
||||
"F18", // [129]
|
||||
"F19", // [130]
|
||||
"F20", // [131]
|
||||
"F21", // [132]
|
||||
"F22", // [133]
|
||||
"F23", // [134]
|
||||
"F24", // [135]
|
||||
"", // [136]
|
||||
"", // [137]
|
||||
"", // [138]
|
||||
"", // [139]
|
||||
"", // [140]
|
||||
"", // [141]
|
||||
"", // [142]
|
||||
"", // [143]
|
||||
"NUM_LOCK", // [144]
|
||||
"SCROLL_LOCK", // [145]
|
||||
"WIN_OEM_FJ_JISHO", // [146]
|
||||
"WIN_OEM_FJ_MASSHOU", // [147]
|
||||
"WIN_OEM_FJ_TOUROKU", // [148]
|
||||
"WIN_OEM_FJ_LOYA", // [149]
|
||||
"WIN_OEM_FJ_ROYA", // [150]
|
||||
"", // [151]
|
||||
"", // [152]
|
||||
"", // [153]
|
||||
"", // [154]
|
||||
"", // [155]
|
||||
"", // [156]
|
||||
"", // [157]
|
||||
"", // [158]
|
||||
"", // [159]
|
||||
"CIRCUMFLEX", // [160]
|
||||
"EXCLAMATION", // [161]
|
||||
"DOUBLE_QUOTE", // [162]
|
||||
"HASH", // [163]
|
||||
"DOLLAR", // [164]
|
||||
"PERCENT", // [165]
|
||||
"AMPERSAND", // [166]
|
||||
"UNDERSCORE", // [167]
|
||||
"OPEN_PAREN", // [168]
|
||||
"CLOSE_PAREN", // [169]
|
||||
"ASTERISK", // [170]
|
||||
"PLUS", // [171]
|
||||
"PIPE", // [172]
|
||||
"HYPHEN_MINUS", // [173]
|
||||
"OPEN_CURLY_BRACKET", // [174]
|
||||
"CLOSE_CURLY_BRACKET", // [175]
|
||||
"TILDE", // [176]
|
||||
"", // [177]
|
||||
"", // [178]
|
||||
"", // [179]
|
||||
"", // [180]
|
||||
"VOLUME_MUTE", // [181]
|
||||
"VOLUME_DOWN", // [182]
|
||||
"VOLUME_UP", // [183]
|
||||
"", // [184]
|
||||
"", // [185]
|
||||
"SEMICOLON", // [186]
|
||||
"EQUALS", // [187]
|
||||
"COMMA", // [188]
|
||||
"MINUS", // [189]
|
||||
"PERIOD", // [190]
|
||||
"SLASH", // [191]
|
||||
"BACK_QUOTE", // [192]
|
||||
"", // [193]
|
||||
"", // [194]
|
||||
"", // [195]
|
||||
"", // [196]
|
||||
"", // [197]
|
||||
"", // [198]
|
||||
"", // [199]
|
||||
"", // [200]
|
||||
"", // [201]
|
||||
"", // [202]
|
||||
"", // [203]
|
||||
"", // [204]
|
||||
"", // [205]
|
||||
"", // [206]
|
||||
"", // [207]
|
||||
"", // [208]
|
||||
"", // [209]
|
||||
"", // [210]
|
||||
"", // [211]
|
||||
"", // [212]
|
||||
"", // [213]
|
||||
"", // [214]
|
||||
"", // [215]
|
||||
"", // [216]
|
||||
"", // [217]
|
||||
"", // [218]
|
||||
"OPEN_BRACKET", // [219]
|
||||
"BACK_SLASH", // [220]
|
||||
"CLOSE_BRACKET", // [221]
|
||||
"QUOTE", // [222]
|
||||
"", // [223]
|
||||
"META", // [224]
|
||||
"ALTGR", // [225]
|
||||
"", // [226]
|
||||
"WIN_ICO_HELP", // [227]
|
||||
"WIN_ICO_00", // [228]
|
||||
"", // [229]
|
||||
"WIN_ICO_CLEAR", // [230]
|
||||
"", // [231]
|
||||
"", // [232]
|
||||
"WIN_OEM_RESET", // [233]
|
||||
"WIN_OEM_JUMP", // [234]
|
||||
"WIN_OEM_PA1", // [235]
|
||||
"WIN_OEM_PA2", // [236]
|
||||
"WIN_OEM_PA3", // [237]
|
||||
"WIN_OEM_WSCTRL", // [238]
|
||||
"WIN_OEM_CUSEL", // [239]
|
||||
"WIN_OEM_ATTN", // [240]
|
||||
"WIN_OEM_FINISH", // [241]
|
||||
"WIN_OEM_COPY", // [242]
|
||||
"WIN_OEM_AUTO", // [243]
|
||||
"WIN_OEM_ENLW", // [244]
|
||||
"WIN_OEM_BACKTAB", // [245]
|
||||
"ATTN", // [246]
|
||||
"CRSEL", // [247]
|
||||
"EXSEL", // [248]
|
||||
"EREOF", // [249]
|
||||
"PLAY", // [250]
|
||||
"ZOOM", // [251]
|
||||
"", // [252]
|
||||
"PA1", // [253]
|
||||
"WIN_OEM_CLEAR", // [254]
|
||||
"" // [255]
|
||||
];
|
||||
|
||||
export default keyboardNameMap;
|
||||
69
src/composables/keyDownHandler/useKeyDownHandler.ts
Normal file
69
src/composables/keyDownHandler/useKeyDownHandler.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { ref, inject } from "vue";
|
||||
import keyboardNameMap from "./keyboardMaps/keyboardNameMap";
|
||||
import keyboardCharMap from "./keyboardMaps/keyboardCharMap";
|
||||
// This catches keys from a physical keyboard, a soft keyboard on a tablet, or a
|
||||
// scanner attached via USB
|
||||
export default function useKeyDownHandler() {
|
||||
interface KeyDownEvent {
|
||||
keyCode: number;
|
||||
shiftKey: boolean;
|
||||
}
|
||||
|
||||
const emitter: any = inject("mitt");
|
||||
const input = ref("");
|
||||
|
||||
// submits newSelfMessage event
|
||||
function handleEnterKey() {
|
||||
// does nothing if input value is empty
|
||||
if (input.value === "") {
|
||||
return;
|
||||
}
|
||||
const message = {
|
||||
content: input.value,
|
||||
signature: "EnriqueH",
|
||||
outgoing: true,
|
||||
modifier: "sf",
|
||||
imgURL: "/test/path",
|
||||
id: null
|
||||
};
|
||||
// fire event with message payload
|
||||
emitter.emit("newSelfMessage", message);
|
||||
}
|
||||
|
||||
function keyDownHandler(e: KeyDownEvent) {
|
||||
// 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", below, for printable characters.
|
||||
// MODIFY keyboardCharMap to suit your needs if you want
|
||||
// more/less/different characters to be considered "printable".
|
||||
let iCol = 0;
|
||||
if (e.shiftKey) {
|
||||
iCol = 1;
|
||||
}
|
||||
console.log(e.shiftKey);
|
||||
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", below, for possible keys.
|
||||
const cmd = keyboardNameMap[e.keyCode];
|
||||
switch (cmd) {
|
||||
case "ENTER":
|
||||
handleEnterKey();
|
||||
break;
|
||||
case "BACK_SPACE":
|
||||
input.value = input.value.slice(0, -1);
|
||||
break;
|
||||
case "ESCAPE":
|
||||
input.value = "";
|
||||
break;
|
||||
default:
|
||||
input.value += ch;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
keyDownHandler,
|
||||
input
|
||||
};
|
||||
}
|
||||
17
src/composables/textWrap/useTextWrap.ts
Normal file
17
src/composables/textWrap/useTextWrap.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export default function useTextWrap() {
|
||||
// text wraps a string to a given width
|
||||
function textWrap({ s, w }: { s: string; w: number }): string[] {
|
||||
// return tspan elements for text with correct size
|
||||
const wrap = (s: string, w: number) =>
|
||||
s.replace(
|
||||
new RegExp(`(?![^\\n]{1,${w}}$)([^\\n]{1,${w}})\\s`, "g"),
|
||||
"$1\n"
|
||||
);
|
||||
const result = wrap(s, w).split("\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
textWrap
|
||||
};
|
||||
}
|
||||
|
|
@ -2,10 +2,17 @@ import { createApp } from "vue";
|
|||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
|
||||
// animation library
|
||||
import anime from "animejs";
|
||||
|
||||
// event handler library
|
||||
import mitt from "mitt";
|
||||
const emitter = mitt();
|
||||
|
||||
createApp(App)
|
||||
.use(store)
|
||||
.use(router)
|
||||
.provide("animejs", anime)
|
||||
.provide("mitt", emitter)
|
||||
.mount("#app");
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
import { provide, inject } from "vue";
|
||||
|
||||
const animeSymbol = Symbol();
|
||||
|
||||
export function provideAnime(anime: any) {
|
||||
provide(animeSymbol, anime);
|
||||
}
|
||||
|
||||
export function useAnime() {
|
||||
const anime = inject(animeSymbol);
|
||||
if (!anime) {
|
||||
console.log("Error! Failed to provide AnimeJS");
|
||||
// throw error, no store provided
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
12
src/shims-vue.d.ts
vendored
12
src/shims-vue.d.ts
vendored
|
|
@ -4,11 +4,13 @@ declare module "*.vue" {
|
|||
export default component;
|
||||
}
|
||||
|
||||
// declare module "anime-js" {
|
||||
// import * as anime from "animejs/lib/anime.es.js";
|
||||
// function anime(): void;
|
||||
// export = anime;
|
||||
// }
|
||||
declare module "anime-js" {
|
||||
namespace anime {
|
||||
import * as anime from "animejs/lib/anime.es.js";
|
||||
function anime(): void;
|
||||
export = anime;
|
||||
}
|
||||
}
|
||||
|
||||
interface Message {
|
||||
content: string;
|
||||
|
|
|
|||
13
src/types/animejs/index.ts
Normal file
13
src/types/animejs/index.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
interface AnimeFuncParams {
|
||||
targets: HTMLElement | SVGGElement | SVGElement;
|
||||
transform: string;
|
||||
easing?: string;
|
||||
duration?: number;
|
||||
offset?: number;
|
||||
begin?: () => void;
|
||||
complete?: () => void;
|
||||
}
|
||||
|
||||
export default interface AnimeFunc {
|
||||
(params: AnimeFuncParams): void | undefined;
|
||||
}
|
||||
18
src/types/message/index.ts
Normal file
18
src/types/message/index.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
export interface Message {
|
||||
content: string;
|
||||
signature: string;
|
||||
outgoing: boolean;
|
||||
modifier: string;
|
||||
imgURL: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface MessageTransform {
|
||||
initialTranslate: string;
|
||||
finalTranslate: string;
|
||||
}
|
||||
|
||||
export interface MessageAnimeFunc {
|
||||
(message: SVGElement, transform: MessageTransform): void;
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +1,18 @@
|
|||
<template>
|
||||
<UIindex />
|
||||
<Microphone />
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted } from 'vue';
|
||||
import UIindex from "@/components/UI/index.vue";
|
||||
import Microphone from "@/components/microphone/index.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "HomeIndex",
|
||||
components: { UIindex, Microphone },
|
||||
});
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import UIindex from "@/components/UI/index.vue";
|
||||
// import Microphone from "@/components/microphone/index.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "HomeIndex",
|
||||
components: { UIindex },
|
||||
setup() {
|
||||
const emitter: any = inject("mitt");
|
||||
emitter.on('newSelfMessage', (payload: any) => console.log('foo', payload) )
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
|
|||
|
|
@ -8569,6 +8569,11 @@ mississippi@^3.0.0:
|
|||
stream-each "^1.1.0"
|
||||
through2 "^2.0.0"
|
||||
|
||||
mitt@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
|
|
|
|||
Loading…
Reference in a new issue