merged css branch into main
This commit is contained in:
parent
725753b7b3
commit
1611cee234
11 changed files with 0 additions and 871 deletions
|
|
@ -1,60 +0,0 @@
|
|||
import { inject } from "vue";
|
||||
import AnimeFunc from "@/types/animejs/index";
|
||||
|
||||
/**
|
||||
* anime js animations used by message view transitions
|
||||
*/
|
||||
export default function useMessageViewAnims() {
|
||||
// imports animejs safely
|
||||
let anime: AnimeFunc;
|
||||
const animeInject: AnimeFunc | undefined = inject("animejs");
|
||||
if (animeInject) anime = animeInject;
|
||||
|
||||
// update message View bottom bound
|
||||
const shiftView = (el: SVGGElement, transform: string) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
|
||||
// stacks message from top to bottom
|
||||
const stackAnimate = (el: Element, transform: string) => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 1000,
|
||||
complete: function() {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// adds new message at the bottom of the list and shifts existing message list
|
||||
const shiftAnimate = (el: Element, transform: string, view: SVGGElement, viewTransform: string) => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 800,
|
||||
begin: function() {
|
||||
shiftView(view, viewTransform);
|
||||
},
|
||||
complete: function() {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
shiftAnimate,
|
||||
stackAnimate,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
:viewBox="scrollView"
|
||||
@click="emittMessage"
|
||||
>
|
||||
<g id="messageView" transform="translate(0, 20)">
|
||||
<g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none">
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<TextBubble :item="item" :key="index" />
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import TextBubble from "@/components/textBubble/index.vue";
|
||||
import { Message } from "@/types/message/index";
|
||||
import { Queue } from "@/modules/queue";
|
||||
import useTransitions from "./viewDetails/transitions";
|
||||
import useScrollView from "@/modules/scrollView";
|
||||
import { defineComponent, reactive, onMounted, onUnmounted, watch } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageView",
|
||||
components: { TextBubble },
|
||||
|
||||
setup() {
|
||||
const renderArr: Message[] = reactive([]);
|
||||
const renderQ = new Queue();
|
||||
|
||||
// Each method will be called on their respective lifecycle event.
|
||||
const { beforeEnter, enter, afterEnter, rendering } = useTransitions();
|
||||
const { scrollView } = useScrollView({
|
||||
targetId: "messageView",
|
||||
});
|
||||
|
||||
const render = (m: Message) => {
|
||||
if (rendering.value) {
|
||||
renderQ.enqueue(m);
|
||||
} else {
|
||||
renderArr.push(m);
|
||||
}
|
||||
};
|
||||
|
||||
watch(rendering, (rendering, _prevRendering) => {
|
||||
if (!rendering) {
|
||||
const m = renderQ.dequeue() as Message | null;
|
||||
if (m) renderArr.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
window.ipcRenderer.on("render-message", (event, payload) => {
|
||||
const m = payload.message;
|
||||
if (m.content) render(m);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.ipcRenderer.removeAllListeners("render-message");
|
||||
});
|
||||
|
||||
return {
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
scrollView,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#messageView {
|
||||
width: 1000px;
|
||||
height: 100vh;
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import {computed} from "vue";
|
||||
|
||||
// Size of "side-gutters" of message window.
|
||||
const margin = 20;
|
||||
const messagePadding = 15;
|
||||
const firstChildMargin = 45;
|
||||
|
||||
|
||||
function calcXPosition(messageWidth: number, windowWidth: number, modifier: string) {
|
||||
let offset = margin;
|
||||
|
||||
if (modifier == "sf") {
|
||||
offset = windowWidth - messageWidth - margin;
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
function calcMessagePosition(modifier: string, messageWidth: number,
|
||||
windowWidth: number, anchorPosition: any) {
|
||||
|
||||
const X = calcXPosition(messageWidth, windowWidth, modifier);
|
||||
|
||||
// Depends on if first child.
|
||||
let Y = firstChildMargin;
|
||||
if (anchorPosition != "none") {
|
||||
Y = anchorPosition + messagePadding;
|
||||
}
|
||||
|
||||
return `translate(${X} ${Y})`;
|
||||
}
|
||||
|
||||
export default calcMessagePosition;
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
<template>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100"
|
||||
height="46"
|
||||
:transform="position"
|
||||
>
|
||||
|
||||
<rect
|
||||
:id="message.id"
|
||||
:class="message.modifier"
|
||||
|
||||
width="100" height="46" rx="10" fill="#58c4fd"
|
||||
/>
|
||||
|
||||
</svg>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { defineComponent, computed, onMounted, ref, reactive } from "vue";
|
||||
|
||||
import calcMessagePosition from "./calcPosition";
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageBubble",
|
||||
|
||||
props: {
|
||||
|
||||
// DOM ID of the previous message.
|
||||
// Null if message is first child.
|
||||
anchor: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
// Passing in the message contents.
|
||||
message: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
|
||||
// e.g. "translate(20 200)"
|
||||
const position = ref("");
|
||||
let anchorPosition: any;
|
||||
|
||||
// Call to update the position variable.
|
||||
const updatePosition = () => {
|
||||
|
||||
// First get anchor's position.
|
||||
if (props.anchor == "none") {
|
||||
anchorPosition = "none";
|
||||
}
|
||||
|
||||
const m = document.getElementById(props.anchor)
|
||||
if (m) {
|
||||
anchorPosition = m.getBoundingClientRect().bottom
|
||||
}
|
||||
|
||||
position.value = calcMessagePosition(
|
||||
props.message.modifier,
|
||||
100,
|
||||
window.innerWidth,
|
||||
anchorPosition
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Message: ${props.message.id}: \n
|
||||
Anchor: ${props.anchor}: ${anchorPosition} \n
|
||||
Position: ${position.value}`
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Assign initial position.
|
||||
updatePosition();
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
// We gotta know when the message above us changes position.
|
||||
|
||||
// Add listener for window resize.
|
||||
window.addEventListener("resize", updatePosition);
|
||||
|
||||
})
|
||||
|
||||
return {
|
||||
position
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<!-- components/messageView/messageView.vue -->
|
||||
|
||||
<template>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
viewBox="0 0 500 500"
|
||||
>
|
||||
|
||||
<g id="messengerGroup">
|
||||
|
||||
<!-- Messages view bounding box -->
|
||||
<rect id="messagesView" data-name="Rectangle 1496" width="500" height="500" rx="15" fill="#ff8e8e"/>
|
||||
|
||||
<!-- List of messages -->
|
||||
<g id="messages" v-for="(item, index) in renderArr" :key="index">
|
||||
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="get"
|
||||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<TextBubble :item="item" :key="index" />
|
||||
</transition>
|
||||
|
||||
</g>
|
||||
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
|
||||
<!-- <svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g id="messagesView">
|
||||
<g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none">
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<TextBubble :item="item" :key="index" />
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
</svg> -->
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import TextBubble from "@/components/textBubble/index.vue";
|
||||
import { Message } from "@/types/message/index";
|
||||
import { Queue } from "@/modules/queue";
|
||||
import useTransitions from "./viewDetails/transitions";
|
||||
import useScrollView from "@/modules/scrollView";
|
||||
import { defineComponent, reactive, onMounted, onUnmounted, watch } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageView",
|
||||
components: { TextBubble },
|
||||
|
||||
setup() {
|
||||
const renderArr: Message[] = reactive([]);
|
||||
const renderQ = new Queue();
|
||||
|
||||
// Each method will be called on their respective lifecycle event.
|
||||
const { beforeEnter, enter, afterEnter, rendering } = useTransitions();
|
||||
// const { scrollView } = useScrollView({
|
||||
// targetId: "messageView",
|
||||
// });
|
||||
|
||||
const render = (m: Message) => {
|
||||
if (rendering.value) {
|
||||
renderQ.enqueue(m);
|
||||
} else {
|
||||
renderArr.push(m);
|
||||
}
|
||||
};
|
||||
|
||||
watch(rendering, (rendering, _prevRendering) => {
|
||||
if (!rendering) {
|
||||
const m = renderQ.dequeue() as Message | null;
|
||||
if (m) renderArr.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
window.ipcRenderer.on("render-message", (event, payload) => {
|
||||
const m = payload.message;
|
||||
if (m.content) render(m);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.ipcRenderer.removeAllListeners("render-message");
|
||||
});
|
||||
|
||||
return {
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#messageView {
|
||||
width: 1000px;
|
||||
height: 100vh;
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
import { ref } from "vue";
|
||||
/**
|
||||
* Calculates vertical and horizontal message offsets
|
||||
*/
|
||||
export default function useOffsetCalculator() {
|
||||
const xOffset = ref(0);
|
||||
const yOffset = ref(0);
|
||||
const firstChildMarginTop = 45;
|
||||
let previousMessageHeight = 0;
|
||||
const messagePadding = 15;
|
||||
|
||||
function calculateX(message: HTMLElement| SVGGElement): void {
|
||||
const computedQuery = window.getComputedStyle(message);
|
||||
const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform);
|
||||
xOffset.value = matrix.m41;
|
||||
}
|
||||
|
||||
function calculateY(messageHeight: number): void {
|
||||
if (previousMessageHeight === 0) {
|
||||
yOffset.value = firstChildMarginTop;
|
||||
} else {
|
||||
yOffset.value += previousMessageHeight + messagePadding;
|
||||
}
|
||||
previousMessageHeight = messageHeight;
|
||||
}
|
||||
|
||||
const calculateMessageOffsets = (msg: HTMLElement): { x: number; y: number } => {
|
||||
const msgRect = msg.getBoundingClientRect();
|
||||
calculateX(msg);
|
||||
calculateY(msgRect.height);
|
||||
const offsets = {
|
||||
x: xOffset.value as number,
|
||||
y: yOffset.value as number
|
||||
};
|
||||
return offsets;
|
||||
}
|
||||
|
||||
return {
|
||||
calculateMessageOffsets,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
/**
|
||||
* single message svg item computed properties
|
||||
*/
|
||||
export default function useComputedBubble(m: string, id: string) {
|
||||
const yMargin = 0;
|
||||
const messageMargin = 20;
|
||||
const messageWidth = ref(0);
|
||||
|
||||
|
||||
// const textFill = computed(() => {
|
||||
// switch (m) {
|
||||
// case "sf":
|
||||
// return "#fff";
|
||||
// default:
|
||||
// return "#000";
|
||||
// }
|
||||
// });
|
||||
|
||||
// const bubbleFill = computed(() => {
|
||||
// switch (m) {
|
||||
// case "sf":
|
||||
// return "#61b4f4";
|
||||
// default:
|
||||
// return "#fff";
|
||||
// }
|
||||
// });
|
||||
|
||||
// const setMessageWidthRef = () => {
|
||||
// const msg = document.getElementById(id);
|
||||
|
||||
// if (msg) {
|
||||
// messageWidth.value = msg.getBoundingClientRect().width;
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
const calculateXoffset = (w: number) => {
|
||||
let offset = messageMargin;
|
||||
|
||||
// If self message, render on righthand side.
|
||||
if (m == "sf") {
|
||||
offset = w - messageMargin - 232
|
||||
|
||||
// Else, render on left.
|
||||
}
|
||||
|
||||
console.log(`${m} : ${offset}`);
|
||||
return offset
|
||||
}
|
||||
|
||||
const calculateYoffset = (h: number) => {
|
||||
|
||||
// Bubble will render a little bit below the screen.
|
||||
return h + yMargin
|
||||
}
|
||||
|
||||
// Where the textBubble is going to initially render.
|
||||
const startingOffset = computed(() => {
|
||||
|
||||
// Get current dimensions of the messenger.
|
||||
const parentView = document.getElementById('messagesView');
|
||||
|
||||
if (parentView) {
|
||||
const dimensions = parentView.getBoundingClientRect();
|
||||
|
||||
const X = calculateXoffset(dimensions.width);
|
||||
const Y = calculateYoffset(dimensions.height);
|
||||
|
||||
return `translate(${X} ${Y})`;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return {
|
||||
startingOffset
|
||||
};
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
import { ref, onMounted } from "vue";
|
||||
import { Ref } from "@/types/vueRef/index";
|
||||
|
||||
/**
|
||||
* handles visualization of single message svg items
|
||||
*/
|
||||
export default function useBubbleDrawer({
|
||||
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 = 12.5;
|
||||
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"));
|
||||
signatureTranslate.value = `translate(-10 ${height})`;
|
||||
}
|
||||
}
|
||||
|
||||
async function drawMessage() {
|
||||
// ignore lint error: await needed for proper render
|
||||
await adjustMessageRect();
|
||||
translateMsgSignature();
|
||||
}
|
||||
|
||||
return {
|
||||
drawMessage,
|
||||
signatureTranslate,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
<template>
|
||||
<g
|
||||
:id="item.id"
|
||||
:class="item.modifier"
|
||||
:transform="startingOffset"
|
||||
>
|
||||
<rect
|
||||
ref="messageRect"
|
||||
x="30"
|
||||
y="10"
|
||||
width="196"
|
||||
height="63"
|
||||
rx="10"
|
||||
:fill="bubbleFill"
|
||||
/>
|
||||
<text
|
||||
font-size="14"
|
||||
font-family="SF Pro Text"
|
||||
ref="messageText"
|
||||
:fill="textFill">
|
||||
|
||||
<tspan dy="16" x="0" v-for="(item, index) in textArr" :key="index">
|
||||
{{ item }}
|
||||
</tspan>
|
||||
|
||||
</text>
|
||||
|
||||
<g :transform="signatureTranslate">
|
||||
<text
|
||||
transform="translate(0, 5)"
|
||||
fill="#000"
|
||||
font-size="10"
|
||||
font-family="SFCompactDisplay-Bold, SF Compact Display"
|
||||
font-weight="700"
|
||||
>
|
||||
|
||||
<tspan xml:space="preserve">
|
||||
{{ item.context }}
|
||||
</tspan>
|
||||
|
||||
</text>
|
||||
|
||||
<text
|
||||
transform="translate(0, 20)"
|
||||
fill="#6f6f6f"
|
||||
font-size="9"
|
||||
font-family="SFCompactDisplay, SF Compact Display"
|
||||
>
|
||||
|
||||
<tspan v-if="item.subContext">
|
||||
{{item.subContext}}
|
||||
</tspan>
|
||||
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import useBubbleDrawer from "./drawer";
|
||||
import useComputedBubble from "./computed";
|
||||
|
||||
import useTextWrap from "@/modules/textWrap";
|
||||
|
||||
import { defineComponent, onMounted, ref, reactive } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TextBubble",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
let textArr: string[] = reactive([]);
|
||||
|
||||
const msgID = ref(props.item.id);
|
||||
const messageRect = ref(`message${msgID.value}`);
|
||||
const messageText = ref(`text${msgID.value}`);
|
||||
|
||||
// Visual attribues of bubble.
|
||||
const { textFill, bubbleFill, startingOffset } = useComputedBubble(
|
||||
props.item.modifier,
|
||||
props.item.id
|
||||
);
|
||||
|
||||
const { textWrap } = useTextWrap();
|
||||
const { drawMessage, signatureTranslate } = useBubbleDrawer({
|
||||
mr: messageRect,
|
||||
tr: messageText,
|
||||
});
|
||||
|
||||
// wraps message text before render
|
||||
textArr = textWrap({
|
||||
s: props.item.content,
|
||||
w: 32,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
drawMessage();
|
||||
});
|
||||
|
||||
return {
|
||||
textFill,
|
||||
bubbleFill,
|
||||
startingOffset,
|
||||
textArr,
|
||||
signatureTranslate,
|
||||
messageText,
|
||||
messageRect,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
/**
|
||||
* Do stuff before, on, and after message enters the view.
|
||||
* Rendering Process consists of the execution of the above
|
||||
* mentioned callbacks followed by the shift or stack animation.
|
||||
* The animation called depends on the height of the message view
|
||||
* relative to the window height. Additionally, the animation will
|
||||
* always be called on the after enter callback, after all the neccesary
|
||||
* calculations have been completed. While all of this is hapenning,
|
||||
* the rendering state is updated throughout the process.
|
||||
*/
|
||||
|
||||
import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
|
||||
import useMessageViewAnims from "./anime";
|
||||
import useOffsetCalculator from './offsetCalculator';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const wH = 500; // window Height
|
||||
const vP = 10; // view padding
|
||||
const mP = 15; // message padding
|
||||
let mH: number; // message Height
|
||||
let vH: number; // view Height
|
||||
let vB: number; // view Bottom Bound
|
||||
let message: HTMLElement | null;
|
||||
let messageOffset = { x: 0, y: 0 };
|
||||
let shift = false;
|
||||
let beforeEnterVH: number;
|
||||
let messageView: SVGGElement;
|
||||
|
||||
export default function useTransitions() {
|
||||
const { calculateMessageOffsets } = useOffsetCalculator();
|
||||
const { shiftAnimate, stackAnimate } = useMessageViewAnims();
|
||||
const rendering = ref(false);
|
||||
|
||||
const animateMessage = async (el: SVGGElement) => {
|
||||
|
||||
// Where the message gets translated to.
|
||||
const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`;
|
||||
|
||||
const viewTransform = `translate(0 ${-vB})`;
|
||||
|
||||
// Shift of view height > window height.
|
||||
if (shift) {
|
||||
await shiftAnimate(el, elTransform, messageView, viewTransform);
|
||||
} else {
|
||||
await stackAnimate(el, elTransform)
|
||||
}
|
||||
rendering.value = false;
|
||||
}
|
||||
|
||||
// const beforeEnter: VueTransitionCallback = () => {
|
||||
// const parentView = document.getElementById('messagesView');
|
||||
|
||||
// if (parentView) {
|
||||
// const dimensions = parentView.getBoundingClientRect();
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// Get height of messageView.
|
||||
const beforeEnter: VueTransitionCallback = () => {
|
||||
rendering.value = true;
|
||||
// query DOM for messageView element
|
||||
const messageViewQuery = document.querySelectorAll("#messageView");
|
||||
messageView = messageViewQuery[0] as SVGGElement;
|
||||
if (messageViewQuery) {
|
||||
beforeEnterVH = messageView.getBBox().height;
|
||||
}
|
||||
}
|
||||
|
||||
const enter: VueTransitionCallback = (el) => {
|
||||
// query DOM for latest message
|
||||
if (el) {
|
||||
message = document.getElementById(el.id);
|
||||
}
|
||||
}
|
||||
|
||||
const afterEnter: VueTransitionCallback = (el) => {
|
||||
|
||||
if (message) messageOffset = calculateMessageOffsets(message);
|
||||
|
||||
if (el) {
|
||||
// calculate message & view heights, as well as view bottom bound
|
||||
mH = el.getBoundingClientRect().height;
|
||||
vH = mH + beforeEnterVH + mP;
|
||||
vB = Math.abs(vH - wH) + vP;
|
||||
|
||||
shift = vH > wH ? true : false;
|
||||
animateMessage(el);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
rendering
|
||||
};
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
/**
|
||||
* single message svg item computed properties
|
||||
*/
|
||||
export default function useComputedBubble(m: string, id: string) {
|
||||
const x = ref(0)
|
||||
const paddingLeft = 30;
|
||||
|
||||
let winW = 350;
|
||||
const messageWidth = ref(0);
|
||||
const messageMarginTop = 75;
|
||||
|
||||
const textFill = computed(() => {
|
||||
switch (m) {
|
||||
case "sf":
|
||||
return "#fff";
|
||||
default:
|
||||
return "#000";
|
||||
}
|
||||
});
|
||||
|
||||
const bubbleFill = computed(() => {
|
||||
switch (m) {
|
||||
case "sf":
|
||||
return "#61b4f4";
|
||||
default:
|
||||
return "#fff";
|
||||
}
|
||||
});
|
||||
|
||||
const updatewinW = computed(() => {
|
||||
const parentView = document.getElementById('messageView');
|
||||
if (parentView) {
|
||||
winW = parentView.getBoundingClientRect().width;
|
||||
}
|
||||
})
|
||||
|
||||
const setMessageWidthRef = async () => {
|
||||
const msg = await document.getElementById(id);
|
||||
if (msg) {
|
||||
messageWidth.value = msg.getBoundingClientRect().width;
|
||||
}
|
||||
}
|
||||
|
||||
const selfMessageMarginRight = 2.5;
|
||||
const calculateXoffset = async () => {
|
||||
switch (m) {
|
||||
case "sf":
|
||||
x.value = winW - messageWidth.value - selfMessageMarginRight;
|
||||
break;
|
||||
default:
|
||||
x.value = paddingLeft;
|
||||
// to center a message
|
||||
// x = messageMargin + (winW -messageWidth) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
const startingOffset = computed(() => {
|
||||
const parentView = document.getElementById('messageView');
|
||||
if (parentView) {
|
||||
const rect = parentView.getBoundingClientRect();
|
||||
let Y = 600;
|
||||
if (rect.height > 500) {
|
||||
Y = rect.height + messageMarginTop;
|
||||
}
|
||||
return `translate(${x.value} ${Y})`;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await setMessageWidthRef();
|
||||
calculateXoffset();
|
||||
})
|
||||
|
||||
return {
|
||||
textFill,
|
||||
bubbleFill,
|
||||
startingOffset
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue