integrate input item

This commit is contained in:
riqo 2020-11-04 16:05:14 -06:00
commit 5e3736caeb
11 changed files with 223 additions and 157 deletions

View 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>

View file

@ -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>

View file

@ -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>

View 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>

View file

@ -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;
}

View file

@ -1,13 +0,0 @@
<template>
<div>
Hello from the mic
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Microphone',
})
</script>

View file

@ -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 {

View file

@ -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;

View file

@ -28,6 +28,7 @@ export default function useKeyDownHandler() {
};
// fire event with message payload
emitter.emit("newSelfMessage", message);
input.value = "";
}
function keyDownHandler(e: KeyDownEvent) {

View file

@ -1,5 +1,5 @@
interface AnimeFuncParams {
targets: HTMLElement | SVGGElement | SVGElement;
targets: Element | HTMLElement | SVGGElement | SVGElement;
translateY?: number;
transform?: string;
easing?: string;

View file

@ -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>