]> Repos - mime-chat/commitdiff
refactor messageItem component
authorriqo <hernandeze2@xavier.edu>
Sun, 25 Oct 2020 20:13:06 +0000 (15:13 -0500)
committerriqo <hernandeze2@xavier.edu>
Sun, 25 Oct 2020 20:13:06 +0000 (15:13 -0500)
src/components/UI/UIDetails/inputItem.vue
src/components/UI/UIDetails/messageItem.vue
src/components/UI/index.vue
src/composables/anims/useMessageItemAnims.ts [new file with mode: 0644]
src/composables/computed/useMessageItemComp.ts [new file with mode: 0644]
src/composables/textWrap/useTextWrap.ts [new file with mode: 0644]
src/composables/useTextBox.ts [deleted file]
src/plugins/anime.ts [deleted file]

index 83eb68ac868559446ed95b8ba55d46dc43438072..cc08402a16644b904dc5510297531bff063e23f0 100644 (file)
@@ -45,5 +45,4 @@ div[contenteditable] {
   font-size: 14;
   text-align: left;
 }
-
 </style>
index a29dd6bc61f087d7dfea4cb778da45c0c828f780..54dd51efa3d85a66036781c73006d73f52a5568e 100644 (file)
@@ -5,8 +5,7 @@
     :transform = "startingOffset"
   >
     <rect
-      ref="bubbleTag"
-      id="#bubble"
+      ref="messageRect"
       x="30"
       y="10"
       width="196"
     <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"
 </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,100 +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;
-      console.log(props)
+    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" || "sf":
-            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>
index 2aeae6c28ab0b6862f1fb1a33d14f66d62f6e31f..64c198dd1c66a526be1a5b2c2a9e1ac842f1e88f 100644 (file)
 <script lang="ts">
 import { defineComponent, inject, onMounted, reactive } from "vue";
 import MessageItem from './UIDetails/messageItem.vue';
-import InputItem from "@/components/UI/UIDetails/inputItem.vue";
+import InputItem from "./UIDetails/inputItem.vue";
 import Messages from "./UIDetails/messages";
 export default defineComponent({
   name: 'UIindex',
   components: { MessageItem, InputItem },
   setup() {
-      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;
-
-      function renderMsg(i: number): void {
-        setTimeout(() => {
-          renderArr.push(messages[i]);
-        }, 2000);
-      }
+    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;
 
-      function runAnim(): void {
-        for (let i = 0; i < messages.length; i++) {
-            renderMsg(i);
-        }
-      }
+    function renderMsg(i: number): void {
+      setTimeout(() => {
+        renderArr.push(messages[i]);
+      }, 2000);
+    }
 
-      async function beforeEnter(el: any) {
-          modifier = el.className.baseVal.substring(0, 2);
+    function runAnim(): void {
+      for (let i = 0; i < messages.length; i++) {
+        renderMsg(i);
       }
+    }
 
-      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();
+    async function beforeEnter(el: any) {
+      modifier = el.className.baseVal.substring(0, 2);
+    }
 
-          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;
+    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();
 
-          switch (modifier) {
-            case "sf":
-              msgOffset.x = winW - msgW;
-              break;
-            case "ai":
-              msgOffset.x = (winW - msgW) / 2;
-              break;
-            default:
-              msgOffset.x = paddingLeft;
-          }
+      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;
 
-          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();
+      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() {
 
       }
diff --git a/src/composables/anims/useMessageItemAnims.ts b/src/composables/anims/useMessageItemAnims.ts
new file mode 100644 (file)
index 0000000..c96fc46
--- /dev/null
@@ -0,0 +1,43 @@
+import { ref, onMounted } from "vue";
+interface Ref {
+  value: string;
+}
+export default function useMessageItemAnims({ mr, tr }: { mr: Ref; tr: Ref }) {
+  const signatureTranslate = ref("");
+  let messageRect: string | SVGRectElement | SVGSVGElement | any;
+  let messageText: string | SVGTextElement | SVGSVGElement | any;
+
+  onMounted(() => {
+    messageRect = mr.value;
+    messageText = tr.value;
+  });
+
+  function adjustMessageRect(): void {
+    // must get dimensions of text box to fit bubble around
+    const padding = 20;
+    const textBox = messageText.getBBox();
+    messageRect.setAttribute("x", textBox.x - padding);
+    messageRect.setAttribute("y", textBox.y - padding);
+    messageRect.setAttribute("width", textBox.width + 2 * padding);
+    messageRect.setAttribute("height", 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
+  };
+}
diff --git a/src/composables/computed/useMessageItemComp.ts b/src/composables/computed/useMessageItemComp.ts
new file mode 100644 (file)
index 0000000..96a5b8a
--- /dev/null
@@ -0,0 +1,40 @@
+import { computed } from "vue";
+// takes in message modifier as param
+export default function useMessageItemComp(m: string) {
+  const textFill = computed(() => {
+    switch (m) {
+      case "fr":
+        return "#000";
+      default:
+        return "#fff";
+    }
+  });
+
+  const bubbleFill = computed(() => {
+    switch (m) {
+      case "sf":
+        return "#61b4f4";
+      case "ai":
+        return "#585858";
+      default:
+        return "#fff";
+    }
+  });
+
+  const startingOffset = computed(() => {
+    switch (m) {
+      case "sf":
+        return "translate(10, 600)";
+      case "ai":
+        return "translate(135, 600)";
+      default:
+        return "translate(20, 600)";
+    }
+  });
+
+  return {
+    textFill,
+    bubbleFill,
+    startingOffset
+  };
+}
diff --git a/src/composables/textWrap/useTextWrap.ts b/src/composables/textWrap/useTextWrap.ts
new file mode 100644 (file)
index 0000000..bf795e0
--- /dev/null
@@ -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
+  };
+}
diff --git a/src/composables/useTextBox.ts b/src/composables/useTextBox.ts
deleted file mode 100644 (file)
index e10821f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import { reactive, onMounted } from "vue";
-export default function useTextBox() {
-  const textArr: string[] = reactive([]);
-
-  function createTextBox(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 textWrap = wrap(s, w).split("\n");
-    return textWrap;
-  }
-
-  function adjustRect(rect: any, text: any): void {
-    // must get dimensions of text box to fit bubble around
-    const padding = 20;
-    const bbox = text.getBBox();
-    rect.setAttribute("x", bbox.x - padding);
-    rect.setAttribute("y", bbox.y - padding);
-    rect.setAttribute("width", bbox.width + 2 * padding);
-    rect.setAttribute("height", bbox.height + 2 * padding);
-  }
-
-  return {
-    textArr,
-    adjustRect,
-    createTextBox
-  };
-}
diff --git a/src/plugins/anime.ts b/src/plugins/anime.ts
deleted file mode 100644 (file)
index 7e2361d..0000000
+++ /dev/null
@@ -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;
-}