working new protocols
This commit is contained in:
parent
a791f973dc
commit
b6b1f3e894
8 changed files with 168 additions and 139 deletions
|
|
@ -6,22 +6,14 @@
|
|||
|
||||
<script lang='ts'>
|
||||
|
||||
import { defineComponent, ref, onMounted } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: "Bubble",
|
||||
|
||||
props: ["modifier", "content", "child"],
|
||||
|
||||
setup(props) {
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
};
|
||||
setup() {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -38,30 +30,18 @@
|
|||
font-size: 14px;
|
||||
padding: 10px;
|
||||
border-radius: 18px;
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
margin-bottom: 4px;
|
||||
// animation-name: bubble-init-anim;
|
||||
// animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
@keyframes bubble-init-anim {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(25px);
|
||||
} to {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
|
||||
.ai-bubble {
|
||||
background-color: #FFFFFF;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.client-bubble {
|
||||
color: white;
|
||||
background-color: #58C4FD;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.ai-first-child {
|
||||
|
|
@ -94,7 +74,6 @@
|
|||
border-top-right-radius: 9px;
|
||||
}
|
||||
|
||||
|
||||
// .notify {
|
||||
// position: absolute;
|
||||
// width: 12px;
|
||||
|
|
|
|||
88
src/render/components/context.vue
Normal file
88
src/render/components/context.vue
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<template>
|
||||
<span :class="`context ${modifier}-context`">
|
||||
<div v-if="modifier==='ai'" class="avatar"></div>
|
||||
{{ contextRef }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
|
||||
import { defineComponent, ref, watch } from 'vue';
|
||||
import { annotateAnim } from "@/render/components/controllers/helpers";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Context",
|
||||
|
||||
props: ["modifier", "context", "uid"],
|
||||
|
||||
setup(props) {
|
||||
|
||||
const contextRef = ref(" ");
|
||||
contextRef.value = props.context;
|
||||
|
||||
watch(() => props.context, (val: string, _oldval: string) => {
|
||||
annotateAnim(props.uid, val, contextRef);
|
||||
});
|
||||
|
||||
return {
|
||||
contextRef
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.context {
|
||||
position: relative;
|
||||
min-height: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "SF Compact Display";
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.ai-context {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.client-context {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.playing {
|
||||
animation-name: message-playback-anim;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
@keyframes message-playback-anim {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4), 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15), 0 0 0 0.4em rgba(195, 195, 195, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55), 0 0 0 0.15em rgba(195, 195, 195, 0.05);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25), 0 0 0 0.55em rgba(195, 195, 195, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { ref, Ref } from "vue";
|
||||
import anime from "animejs";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
|
||||
export function animateTextInput () {
|
||||
|
|
@ -93,7 +92,7 @@ export function annotateAnim (uid: string, val: string, contextRef: Ref) {
|
|||
anime({
|
||||
targets: `#${uid} span`,
|
||||
opacity: [1, 0],
|
||||
duration: 500,
|
||||
duration: 250,
|
||||
easing: 'easeOutExpo'
|
||||
})
|
||||
|
||||
|
|
@ -105,7 +104,7 @@ export function annotateAnim (uid: string, val: string, contextRef: Ref) {
|
|||
anime({
|
||||
targets: `#${uid} span`,
|
||||
opacity: [0, 1],
|
||||
duration: 500,
|
||||
duration: 250,
|
||||
easing: 'easeOutExpo'
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import draggify from "@/render/composables/useDraggify";
|
|||
|
||||
import useTextInputController from
|
||||
"@/render/components/controllers/inputItem.control.text";
|
||||
import useAudioInputController from
|
||||
// import useAudioInputController from
|
||||
"@/render/components/controllers/inputItem.control.audio";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -51,7 +51,8 @@ export default defineComponent({
|
|||
|
||||
// Controllers for text and audio.
|
||||
const { typing } = useTextInputController(elementX)
|
||||
const { recording } = useAudioInputController(typing)
|
||||
// const { recording } = useAudioInputController(typing)
|
||||
const recording = false;
|
||||
|
||||
return {
|
||||
elementX,
|
||||
|
|
|
|||
|
|
@ -8,19 +8,21 @@
|
|||
:child="calcChild(index, content.length)"
|
||||
/>
|
||||
|
||||
<span class="context">
|
||||
<div v-if="modifier==='ai'" class="avatar"></div>
|
||||
{{ contextRef }}
|
||||
</span>
|
||||
<Context
|
||||
:modifier="modifier"
|
||||
:context="context"
|
||||
:uid="uid"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
|
||||
import { defineComponent, ref, Ref, onMounted, watch } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import Bubble from "@/render/components/bubble.vue";
|
||||
import { annotateAnim, calcChild } from "@/render/components/controllers/helpers";
|
||||
import Context from "@/render/components/context.vue";
|
||||
import { calcChild } from "@/render/components/controllers/helpers";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Message",
|
||||
|
|
@ -28,25 +30,14 @@
|
|||
props: ["modifier", "content", "context", "uid"],
|
||||
|
||||
components: {
|
||||
Bubble
|
||||
Bubble,
|
||||
Context
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
|
||||
const contextRef = ref(" ");
|
||||
contextRef.value = props.context;
|
||||
|
||||
watch(() => props.context, (val: string, oldval: string) => {
|
||||
annotateAnim(props.uid, val, contextRef);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
});
|
||||
setup() {
|
||||
|
||||
return {
|
||||
calcChild,
|
||||
contextRef
|
||||
calcChild
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -57,85 +48,41 @@
|
|||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.message {
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
animation-name: message-init-anim;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
.message {
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
animation-name: message-init-anim;
|
||||
animation-duration: 0.25s;
|
||||
}
|
||||
|
||||
@keyframes message-init-anim {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
} to {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
@keyframes message-init-anim {
|
||||
from {
|
||||
opacity: 0;
|
||||
} to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.message:first-child {
|
||||
margin-top: 55px;
|
||||
}
|
||||
.message:first-child {
|
||||
margin-top: 55px;
|
||||
}
|
||||
|
||||
.message:last-child {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.message:last-child {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.client-message {
|
||||
@extend .message;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.client-message {
|
||||
@extend .message;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.ai-message {
|
||||
@extend .message;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.context {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "SF Compact Display";
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.playing {
|
||||
animation-name: message-playback-anim;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
@keyframes message-playback-anim {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4), 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15), 0 0 0 0.4em rgba(195, 195, 195, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55), 0 0 0 0.15em rgba(195, 195, 195, 0.05);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25), 0 0 0 0.55em rgba(195, 195, 195, 0.45);
|
||||
}
|
||||
}
|
||||
.ai-message {
|
||||
@extend .message;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
|
||||
import { defineComponent, onMounted, onUnmounted } from "vue";
|
||||
import { defineComponent } from "vue";
|
||||
import InputItem from "@/render/components/inputItem.vue";
|
||||
import Settings from "@/render/components/settings.vue";
|
||||
import Message from "@/render/components/message.vue";
|
||||
|
|
|
|||
|
|
@ -1,28 +1,32 @@
|
|||
|
||||
|
||||
export default function useScroll(element: string) {
|
||||
|
||||
let isScrolledToBottom: boolean;
|
||||
const view = document.getElementById(element)
|
||||
export default function useScroll(elementId: string) {
|
||||
|
||||
// Update isScrolledToBottom
|
||||
const updateScrollRef = () => {
|
||||
if (view) isScrolledToBottom = view.scrollHeight - view.clientHeight <= view.scrollTop + 1;
|
||||
return isScrolledToBottom;
|
||||
const isScrolledToBottom = () => {
|
||||
const el = document.getElementById(elementId);
|
||||
|
||||
if (el) {
|
||||
return el.scrollHeight - el.clientHeight <= el.scrollTop + 30;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Adjust scroll after we add content to the messenger.
|
||||
const adjustScroll = () => {
|
||||
if (view) {
|
||||
view.scrollTo({
|
||||
top: view.scrollHeight - view.clientHeight,
|
||||
const el = document.getElementById(elementId);
|
||||
|
||||
if (el) {
|
||||
el.scrollTo({
|
||||
top: el.scrollHeight - el.clientHeight,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
updateScrollRef,
|
||||
isScrolledToBottom,
|
||||
adjustScroll,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,20 +2,31 @@
|
|||
import { ref, Ref } from "vue";
|
||||
import useScroll from "@/render/composables/useScroll";
|
||||
|
||||
const { isScrolledToBottom, adjustScroll } = useScroll("messenger");
|
||||
|
||||
export const messages: Ref<Array<Message>> = ref([]);
|
||||
|
||||
export const setMessages: IpcListenerCallback<Array<Message>> = (payload) => {
|
||||
messages.value = payload as Array<Message>;
|
||||
setTimeout(() => {
|
||||
adjustScroll();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
export const addMessage: IpcListenerCallback<Message> = (payload) => {
|
||||
const bottom = isScrolledToBottom();
|
||||
messages.value.push(payload as Message);
|
||||
if (bottom) {
|
||||
setTimeout(() => {
|
||||
adjustScroll();
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
|
||||
export const updateMessage: IpcListenerCallback<Annotation> = (payload) => {
|
||||
const annotation = payload as Annotation;
|
||||
|
||||
for (let i in messages.value) {
|
||||
for (const i in messages.value) {
|
||||
|
||||
if (messages.value[i].uid == annotation.uid) {
|
||||
|
||||
|
|
@ -36,7 +47,7 @@ export const updateMessage: IpcListenerCallback<Annotation> = (payload) => {
|
|||
export const deleteMessage: IpcListenerCallback<string> = (payload) => {
|
||||
const uid = payload as string;
|
||||
|
||||
for (var i = 0; i < messages.value.length; i++) {
|
||||
for (let i = 0; i < messages.value.length; i++) {
|
||||
if (messages.value[i].uid === uid) {
|
||||
messages.value.splice(i, 1);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue