integrate input item
This commit is contained in:
parent
8062a09552
commit
5e3736caeb
11 changed files with 223 additions and 157 deletions
39
src/components/AI/index.vue
Normal file
39
src/components/AI/index.vue
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<defs>
|
||||
<radialGradient
|
||||
id="radial-gradient"
|
||||
cx="0.5"
|
||||
cy="1"
|
||||
r="0.54"
|
||||
gradientTransform="translate(-1.489 1.5) rotate(-90) scale(1 1.989)"
|
||||
gradientUnits="objectBoundingBox"
|
||||
>
|
||||
<stop offset="0" stop-color="#fff" />
|
||||
<stop offset="1" stop-color="#e6e6e6" />
|
||||
</radialGradient>
|
||||
<filter id="Rectangle_410" x="0" y="0" width="380" height="530" filterUnits="userSpaceOnUse">
|
||||
<feOffset dy="3" input="SourceAlpha" />
|
||||
<feGaussianBlur stdDeviation="5" result="blur" />
|
||||
<feFlood flood-opacity="0.129" />
|
||||
<feComposite operator="in" in2="blur" />
|
||||
<feComposite in="SourceGraphic" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g transform="matrix(1, 0, 0, 1, 0, 0)" filter="url(#Rectangle_410)">
|
||||
<rect
|
||||
id="Rectangle_410-2"
|
||||
data-name="Rectangle 410"
|
||||
width="350"
|
||||
height="500"
|
||||
rx="20"
|
||||
fill="url(#radial-gradient)"
|
||||
/>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
export default defineComponent({
|
||||
name: "AI",
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
<template>
|
||||
<foreignObject x="10" y="10" width="100%" height="100%">
|
||||
<foreignObject class="inputContainer" :x="x" y="450" width="55%" height="50%">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div contenteditable
|
||||
v-if="input.length > 0"
|
||||
>
|
||||
{{ input }}
|
||||
<div class="inputBubble" contenteditable v-show="input.length > 0">
|
||||
<p>{{ input }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
|
|
@ -12,11 +10,30 @@
|
|||
|
||||
<script lang="ts">
|
||||
import useKeyDownHandler from "@/composables/keyDownHandler/useKeyDownHandler";
|
||||
import { defineComponent, onUnmounted } from "vue";
|
||||
import AnimeFunc from "@/types/animejs/index";
|
||||
import {
|
||||
defineComponent,
|
||||
onUnmounted,
|
||||
computed,
|
||||
ref,
|
||||
onMounted,
|
||||
watch,
|
||||
inject,
|
||||
} from "vue";
|
||||
export default defineComponent({
|
||||
name: "InputItem",
|
||||
setup() {
|
||||
const {keyDownHandler, input} = useKeyDownHandler();
|
||||
const emitter: any = inject("mitt");
|
||||
emitter.on("newSelfMessage", (payload: any) => console.log("foo", payload));
|
||||
const { keyDownHandler, input } = useKeyDownHandler();
|
||||
const inputHeight = ref(42);
|
||||
let inputBubble: HTMLElement;
|
||||
const inputWidth = ref(0);
|
||||
|
||||
// imports animejs safely
|
||||
let anime: AnimeFunc;
|
||||
const animeInject: AnimeFunc | undefined = inject("animejs");
|
||||
if (animeInject) anime = animeInject;
|
||||
|
||||
// add window event listener
|
||||
window.addEventListener("keydown", keyDownHandler);
|
||||
|
|
@ -25,24 +42,63 @@ export default defineComponent({
|
|||
window.removeEventListener("keydown", keyDownHandler);
|
||||
});
|
||||
|
||||
watch(input, async (input, prevInput) => {
|
||||
const inputDivs = await document.getElementsByClassName("inputBubble");
|
||||
const height = inputDivs[0].getBoundingClientRect().height;
|
||||
inputWidth.value = inputDivs[0].getBoundingClientRect().width;
|
||||
const foreignObjectDiv = document.getElementsByClassName(
|
||||
"inputContainer"
|
||||
);
|
||||
if (height !== inputHeight.value) {
|
||||
inputHeight.value = height;
|
||||
}
|
||||
const foreignEl = foreignObjectDiv[0] as HTMLElement;
|
||||
if (inputHeight.value === 0) {
|
||||
anime({
|
||||
targets: foreignEl,
|
||||
translateY: -10,
|
||||
});
|
||||
} else if (inputHeight.value > 36) {
|
||||
anime({
|
||||
targets: foreignEl,
|
||||
translateY: -inputHeight.value + 30,
|
||||
easing: "easeOutQuad",
|
||||
duration: 150,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const x = computed(() => {
|
||||
return `calc(50% - ${inputWidth.value / 2})`;
|
||||
});
|
||||
|
||||
return {
|
||||
input
|
||||
input,
|
||||
x,
|
||||
};
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div[contenteditable] {
|
||||
width: auto;
|
||||
max-width: 200px;
|
||||
max-width: 180px;
|
||||
height: auto;
|
||||
min-height: 36px;
|
||||
display: table;
|
||||
padding: 7px 15px 7px 15px;
|
||||
justify-items: center;
|
||||
border: 0;
|
||||
border-radius: 25px;
|
||||
border-radius: 20px;
|
||||
color: #fff;
|
||||
background-color: #61b4f4;
|
||||
font-size: 14;
|
||||
text-align: left;
|
||||
p {
|
||||
max-width: 150px;
|
||||
overflow-wrap: break-word;
|
||||
padding: 10px 15px 10px 15px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,11 @@
|
|||
<template>
|
||||
<g
|
||||
:id="item.id"
|
||||
:class="item.modifier"
|
||||
:transform = "startingOffset"
|
||||
>
|
||||
<rect
|
||||
ref="messageRect"
|
||||
x="30"
|
||||
y="10"
|
||||
width="196"
|
||||
height="63"
|
||||
rx="20"
|
||||
:fill="bubbleFill"
|
||||
/>
|
||||
<text
|
||||
font-size="14"
|
||||
font-family="SF Pro"
|
||||
ref="messageText"
|
||||
:fill="textFill"
|
||||
>
|
||||
<tspan
|
||||
dy="16"
|
||||
x="0"
|
||||
v-for="(item, index) in textArr"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</tspan>
|
||||
<g :id="item.id" :class="item.modifier" :transform="startingOffset">
|
||||
<rect ref="messageRect" x="30" y="10" width="196" height="63" rx="20" :fill="bubbleFill" />
|
||||
<text font-size="14" font-family="SF Pro" ref="messageText" :fill="textFill">
|
||||
<tspan dy="16" x="0" v-for="(item, index) in textArr" :key="index">{{ item }}</tspan>
|
||||
</text>
|
||||
<g :transform="signatureTranslate">
|
||||
<image
|
||||
xlink:href="profile.png"
|
||||
width="29"
|
||||
height="29"
|
||||
fill="#b5b5b5"
|
||||
clip-path="url(#clip)"
|
||||
/>
|
||||
<image xlink:href="profile.png" width="29" height="29" fill="#b5b5b5" clip-path="url(#clip)" />
|
||||
<text
|
||||
transform="translate(36, 17)"
|
||||
fill="#888"
|
||||
|
|
@ -45,23 +15,23 @@
|
|||
>
|
||||
<tspan v-if="item.outgoing">You to</tspan>
|
||||
<tspan v-else>From</tspan>
|
||||
<tspan xml:space="preserve" fill="#000"> {{ item.signature }}</tspan>
|
||||
<tspan xml:space="preserve" fill="#000">{{ item.signature }}</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, reactive } from 'vue';
|
||||
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";
|
||||
import useTextWrap from "@/composables/textWrap/useTextWrap";
|
||||
export default defineComponent({
|
||||
name: "MessageItem",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
|
|
@ -71,22 +41,24 @@ export default defineComponent({
|
|||
const messageRect = ref(`message${msgID.value}`);
|
||||
const messageText = ref(`text${msgID.value}`);
|
||||
|
||||
const { textFill, bubbleFill, startingOffset } = useMessageItemComp(props.item.modifier);
|
||||
const { textFill, bubbleFill, startingOffset } = useMessageItemComp(
|
||||
props.item.modifier
|
||||
);
|
||||
const { textWrap } = useTextWrap();
|
||||
const { drawMessage, signatureTranslate } = useMessageItemAnims({
|
||||
mr: messageRect,
|
||||
tr: messageText,
|
||||
})
|
||||
});
|
||||
|
||||
// wraps message text before render
|
||||
textArr = textWrap({
|
||||
s: props.item.content,
|
||||
w: 32
|
||||
w: 32,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
drawMessage();
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
textFill,
|
||||
|
|
@ -95,8 +67,8 @@ export default defineComponent({
|
|||
textArr,
|
||||
signatureTranslate,
|
||||
messageText,
|
||||
messageRect
|
||||
}
|
||||
messageRect,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
64
src/components/UI/UIDetails/titleBar.vue
Normal file
64
src/components/UI/UIDetails/titleBar.vue
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="linear-gradient"
|
||||
x1="0.5"
|
||||
y1="-1.438"
|
||||
x2="0.5"
|
||||
y2="0.633"
|
||||
gradientUnits="objectBoundingBox"
|
||||
>
|
||||
<stop offset="0" stop-color="#fff33b" stop-opacity="0" />
|
||||
<stop offset="0.152" stop-color="#ffde46" stop-opacity="0.141" />
|
||||
<stop offset="0.467" stop-color="#ffa764" stop-opacity="0.435" />
|
||||
<stop offset="0.581" stop-color="#ff916f" stop-opacity="0.541" />
|
||||
<stop offset="1" stop-color="#ff5782" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linear-gradient-2"
|
||||
x1="0.498"
|
||||
y1="0.728"
|
||||
x2="0.498"
|
||||
y2="-0.433"
|
||||
gradientUnits="objectBoundingBox"
|
||||
>
|
||||
<stop offset="0" stop-color="#f7cf83" />
|
||||
<stop offset="1" stop-color="#fff" />
|
||||
</linearGradient>
|
||||
<rect id="rect" width="29" height="29" rx="10" />
|
||||
<clipPath id="clip">
|
||||
<use xlink:href="#rect" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<g id="titlebar" transform="translate(0, 0)">
|
||||
<g data-name="Group 73" transform="translate(20 20)">
|
||||
<ellipse
|
||||
id="Oval"
|
||||
cx="8.134"
|
||||
cy="8.134"
|
||||
rx="8.134"
|
||||
ry="8.134"
|
||||
transform="translate(0 0)"
|
||||
fill="url(#linear-gradient)"
|
||||
/>
|
||||
<ellipse
|
||||
id="Oval-2"
|
||||
data-name="Oval"
|
||||
cx="8.134"
|
||||
cy="8.134"
|
||||
rx="8.134"
|
||||
ry="8.134"
|
||||
transform="translate(27 0)"
|
||||
fill="url(#linear-gradient-2)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
export default defineComponent({
|
||||
name: "TitleBar",
|
||||
});
|
||||
</script>
|
||||
|
|
@ -6,37 +6,8 @@
|
|||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
@click="renderMessage"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="linear-gradient"
|
||||
x1="0.5"
|
||||
y1="-1.438"
|
||||
x2="0.5"
|
||||
y2="0.633"
|
||||
gradientUnits="objectBoundingBox"
|
||||
>
|
||||
<stop offset="0" stop-color="#fff33b" stop-opacity="0" />
|
||||
<stop offset="0.152" stop-color="#ffde46" stop-opacity="0.141" />
|
||||
<stop offset="0.467" stop-color="#ffa764" stop-opacity="0.435" />
|
||||
<stop offset="0.581" stop-color="#ff916f" stop-opacity="0.541" />
|
||||
<stop offset="1" stop-color="#ff5782" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linear-gradient-2"
|
||||
x1="0.498"
|
||||
y1="0.728"
|
||||
x2="0.498"
|
||||
y2="-0.433"
|
||||
gradientUnits="objectBoundingBox"
|
||||
>
|
||||
<stop offset="0" stop-color="#f7cf83" />
|
||||
<stop offset="1" stop-color="#fff" />
|
||||
</linearGradient>
|
||||
<rect id="rect" width="29" height="29" rx="10" />
|
||||
<clipPath id="clip">
|
||||
<use xlink:href="#rect" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<AI />
|
||||
|
||||
<g id="cardsDiv">
|
||||
<g
|
||||
v-for="(item, index) in renderArr"
|
||||
|
|
@ -51,70 +22,49 @@
|
|||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<MessageItem
|
||||
:item="item"
|
||||
:key="index"
|
||||
/>
|
||||
<MessageItem :item="item" :key="index" />
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
<g id="titlebar" transform="translate(0, 0)">
|
||||
<g data-name="Group 73" transform="translate(20 20)">
|
||||
<ellipse
|
||||
id="Oval"
|
||||
cx="8.134"
|
||||
cy="8.134"
|
||||
rx="8.134"
|
||||
ry="8.134"
|
||||
transform="translate(0 0)"
|
||||
fill="url(#linear-gradient)"
|
||||
/>
|
||||
<ellipse
|
||||
id="Oval-2"
|
||||
data-name="Oval"
|
||||
cx="8.134"
|
||||
cy="8.134"
|
||||
rx="8.134"
|
||||
ry="8.134"
|
||||
transform="translate(27 0)"
|
||||
fill="url(#linear-gradient-2)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<InputItem />
|
||||
<TitleBar />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive } from "vue";
|
||||
import MessageItem from './UIDetails/messageItem.vue';
|
||||
import MessageItem from "./UIDetails/messageItem.vue";
|
||||
import AI from "../AI/index.vue";
|
||||
import InputItem from "./UIDetails/inputItem.vue";
|
||||
import TitleBar from "./UIDetails/titleBar.vue";
|
||||
import Messages from "./UIDetails/messages";
|
||||
import useUIindexAnims from "@/composables/anims/useUIindexAnims";
|
||||
export default defineComponent({
|
||||
name: 'UIindex',
|
||||
components: { MessageItem },
|
||||
name: "UIindex",
|
||||
components: { AI, MessageItem, InputItem, TitleBar },
|
||||
setup() {
|
||||
const renderArr: Message[] = reactive([])
|
||||
const renderArr: Message[] = reactive([]);
|
||||
const messages = Messages;
|
||||
const count = ref(0);
|
||||
|
||||
const { beforeEnter, enter, afterEnter } = useUIindexAnims();
|
||||
|
||||
const renderMessage = () => {
|
||||
if (count.value < messages.length) {
|
||||
renderArr.push(messages[count.value])
|
||||
count.value++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (count.value < messages.length) {
|
||||
renderArr.push(messages[count.value]);
|
||||
count.value++;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
renderMessage,
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter
|
||||
}
|
||||
renderMessage,
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
@ -123,7 +73,7 @@ export default defineComponent({
|
|||
#messenger {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
background-color: #E6E6E6;
|
||||
background-color: #e6e6e6;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
Hello from the mic
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'Microphone',
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -124,17 +124,15 @@ export default function useUIindexAnims() {
|
|||
}
|
||||
|
||||
function enter(el: SVGGElement): void {
|
||||
console.log(window.getComputedStyle(el).transform)
|
||||
msg = document.getElementById(el.id);
|
||||
}
|
||||
|
||||
const afterEnter = (el: SVGGElement) => {
|
||||
function afterEnter(el: SVGGElement) {
|
||||
if (msg) calculateMessageOffsets(msg);
|
||||
if (scrollAnim) {
|
||||
scroll -= el.getBBox().height + messagePadding;
|
||||
}
|
||||
addMessage(el);
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ export default function useMessageItemComp(m: string) {
|
|||
const cardsDiv = document.getElementById('cardsDiv')
|
||||
if (cardsDiv) {
|
||||
const rect = cardsDiv.getBoundingClientRect();
|
||||
const sfX = 115;
|
||||
const sfX = 120;
|
||||
const aiX = 200;
|
||||
const dX = 20;
|
||||
const dX = 40;
|
||||
let Y = 600;
|
||||
if (rect.height > 500) {
|
||||
Y = rect.height + 75;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export default function useKeyDownHandler() {
|
|||
};
|
||||
// fire event with message payload
|
||||
emitter.emit("newSelfMessage", message);
|
||||
input.value = "";
|
||||
}
|
||||
|
||||
function keyDownHandler(e: KeyDownEvent) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
interface AnimeFuncParams {
|
||||
targets: HTMLElement | SVGGElement | SVGElement;
|
||||
targets: Element | HTMLElement | SVGGElement | SVGElement;
|
||||
translateY?: number;
|
||||
transform?: string;
|
||||
easing?: string;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
<template>
|
||||
<UIindex />
|
||||
<UIindex />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject } from 'vue';
|
||||
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) )
|
||||
}
|
||||
emitter.on("newSelfMessage", (payload: any) => console.log("foo", payload));
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue