html, body {
margin: 0;
padding: 0;
+ background-color: #EBEBEB;
}
#app {
height: 100vh;
width: 100vw;
- background-color: #EBEBEB;
border-radius: 15px;
}
// create main window.
await createWindow({
- width: 350,
+ width: 600,
height: 500,
resizable: true
});
text: string;
audio: boolean | Buffer;
};
- avatar: string;
context: string;
- subContext: string;
modifier: string;
- time: string;
id: string;
}
--- /dev/null
+
+// When user clicks and holds inputItem.
+function onMouseDown (e: any) {
+ window.addEventListener('mousemove', onMouseMove, true);
+}
+
+// When user drags inputItem.
+function onMouseMove (e: any) {
+
+ const element = document.getElementById('inputItem')
+
+ if (element) {
+
+ const inputItemRect = element.getBoundingClientRect()
+ inputItemX.value = inputItemRect.left + e.movementX
+ inputItemY.value = inputItemRect.top + e.movementY
+
+ }
+
+}
+
+// When user lets go of inputItem.
+function onMouseUp (e: any) {
+
+}
+
--- /dev/null
+<template>
+ <div id=inputItem
+ :style="{ top: `${inputItemY}px`, left: `${inputItemX}px` }">
+
+ </div>
+</template>
+
+<script lang="ts">
+
+import { defineComponent, onMounted, ref, onUnmounted } from "vue";
+
+export default defineComponent({
+ name: "InputItem",
+
+ setup() {
+
+ let inputItemX = ref(0)
+ let inputItemY = ref(0)
+
+ let xShort: object = {
+ distance: Number,
+ side: String
+ }
+
+ let percentX: number;
+ let percentY: number;
+
+ // Draggable on mousedown.
+ const mouseDown = (e: any) => {
+ window.addEventListener('mousemove', divMove, true);
+ }
+
+ // Update the positional refs.
+ const mouseUp = (e: any) => {
+ window.removeEventListener('mousemove', divMove, true);
+
+
+
+ const winW = window.innerWidth
+ const winH = window.innerHeight
+ console.log(`Window dimensions: W${winW} H${winH}`)
+
+ }
+
+ // Called on mousemove event. Updates the inputItem cords when user is
+ // dragging it.
+ const divMove = (e: any) => {
+ const element = document.getElementById('inputItem')
+
+ if (element) {
+
+ const inputItemRect = element.getBoundingClientRect()
+ inputItemX.value = inputItemRect.left + e.movementX
+ inputItemY.value = inputItemRect.top + e.movementY
+
+ }
+
+ }
+
+ // Adjust position of inputItem on window resize.
+ // If inputItem is within 10% of corner, keep the distances from that
+ // corner fixed, else resize relative to percentages.
+ const handleResize = (e: any) => {
+
+ // Adjust X:
+ // Is X close to a vertical side?
+ // If so: position fixed
+ if (inputItemX.onSide) {
+
+ if (inputItemX.rightSide) {
+ inputItemX.value = window.innerWidth - xShort
+ } else {
+ inputItemX.value = xShort
+ }
+
+ // Else: position relative
+ } else {
+ inputItemX.value = window.innerWidth * percentX
+ }
+
+ // Initialize InputPosition.
+ inputItemX.value = 300
+ inputItemY.value = 300
+ percentX = 0.5
+ percentY = 0.5
+
+ onMounted(() => {
+
+ const element = document.getElementById('inputItem')
+
+ if (element) {
+ element.addEventListener('mousedown', mouseDown, false);
+ }
+
+ window.addEventListener('mouseup', mouseUp, false);
+ window.addEventListener('resize', handleResize, false)
+
+ });
+
+ return {
+ inputItemX,
+ inputItemY
+ }
+ }
+
+});
+
+</script>
+
+<style lang="scss" scoped>
+
+ #inputItem {
+ position: absolute;
+
+ width: 30px;
+ height: 30px;
+
+ border-radius: 19px;
+
+ z-index: 20;
+
+ top: 200px;
+ right: 0px;
+
+ border-style: solid;
+ border-width: 4px;
+ border-color: #C3C3C3;
+
+ background-color: white;
+
+ }
+
+</style>
\ No newline at end of file
:key="message.id"
>
+ <!-- Three types of messages: self (sf), friend (fr), and crimata (ai) -->
+ <!-- !denoted by the modifier attribute -->
+
<!-- Includes bubble and context. -->
<div class="messageBox" :id="`${message.modifier}MessageBox`">
class="bubble"
:id="`${message.modifier}Bubble`"
>
- {{ message.content }}
+ {{ message.content.text }}
</div>
<!-- message context -->
<span class="context">
- <!-- Render Crimata icon or initials. -->
- <div v-if="message.avatar == 'crimata'" class="photo">
+ <!-- Render Crimata icon or friend's initials. -->
+ <div v-if="message.modifier == 'ai'" class="photo">
<img src="@/assets/crimata.svg"/>
</div>
- <div v-else class="photo">
- {{ message.avatar }}
+ <!-- Render Crimata icon or friend's initials. -->
+ <div v-if="message.modifier == 'fr'" class="photo">
+ {{ message.context[0] }}
</div>
{{ message.context }}
align-items: flex-end;
}
+ #frMessage {
+ align-items: flex-start;
+ }
+
+ .messageBox {
+ display: flex;
+ flex-direction: column;
+ }
+
#aiMessageBox {
margin-left: 20px;
+ align-items: flex-start;
}
#sfMessageBox {
margin-right: 20px;
+ align-items: flex-end;
+ }
+
+ #frMessageBox {
+ margin-left: 20px;
+ align-items: flex-start;
}
.bubble {
color: white;
}
+ #frBubble {
+ background-color: white;
+ }
+
.context {
display: flex;
align-items: center;
font-family: "SF Compact Display";
font-size: 12px;
font-weight: bold;
- margin-left: 7px;
margin-top: 5px;
}
--- /dev/null
+
+// Update inputItem position on window resize.
+// Gets called on window.resize event.
+function handleWindowResize (e: any) {
+
+}
+
--- /dev/null
+ // Snap to the nearest window border and update percentages. Called when
+ // user stops dragging the inputItem.
+ const mouseUp = (e: any) => {
+ window.removeEventListener('mousemove', divMove, true);
+
+ const winW = window.innerWidth
+ const winH = window.innerHeight
+ console.log(`Window dimensions: W${winW} H${winH}`)
+
+ // First, are we changing inputItemX or inputItemY?
+
+ let xShort = winW - inputItemX.value
+ if (xShort > winW / 2) {
+ xShort = inputItemX.value
+ }
+
+ let yShort = winH - inputItemY.value
+ if (yShort > winH / 2) {
+ yShort = inputItemY.value
+ }
+
+ const shortest = (xShort < yShort) ? "inputItemX" : "inputItemY"
+
+ // Then, are we tranlating it positive or negative?
+ // To answer this, we see which side is it closer to.
+ // We also update percentages to aid in window resizing (handleResize).
+
+ if (shortest == "inputItemX") {
+ if (inputItemX.value < winW / 2) {
+ inputItemX.value = 0
+ percentX = 0.0
+ } else {
+ inputItemX.value = winW - 38
+ percentX = 1.0
+ }
+ percentY = inputItemY.value / winH
+ } else {
+ if (inputItemY.value < winH / 2) {
+ inputItemY.value = 0
+ percentY = 0.0
+ } else {
+ inputItemY.value = winH - 38
+ percentY = 1.0
+ }
+ percentX = inputItemX.value / winW
+
+ }
+ console.log(`Percents updated: iX: ${percentX} iY: ${percentY}`)
+ }
+
+
+
+
+ if (percentX == 1.0) {
+ inputItemX.value = window.innerWidth * percentX - 38
+ } else {
+ inputItemX.value = window.innerWidth * percentX
+ }
+
+ if (percentY == 1.0) {
+ inputItemY.value = window.innerHeight * percentY - 38
+ } else {
+ inputItemY.value = window.innerHeight * percentY
+ }
+
+ }
\ No newline at end of file
export interface Message {
- content: string;
- avatar: string;
+ content: {
+ text: string;
+ audio: boolean | Buffer;
+ };
context: string;
- subContext: string;
modifier: string;
id: string;
- time: string;
}
interface MessageTransform {
<template>
<TextAudioInput />
+ <!-- <InputItem /> -->
<!-- List of message bubbles. -->
<div id="messenger" >
import TextAudioInput from "@/components/taInput/index.vue";
import { Message } from "@/types/message/index";
import MessageItem from '@/components/messageItem.vue'
+// import InputItem from "@/components/inputItem.vue";
export default defineComponent({
name: "Messenger",
components: {
TextAudioInput,
MessageItem,
+ // InputItem
},
setup() {
// Render a message.
const render = (message: Message) => {
messages.push(message);
- console.log(`Pushing: ${message.modifier}: ${message.avatar}, ${message.content}`);
+ console.log(`Pushing: ${message.modifier}: ${message.content.text} ${message.context}`);
}
onMounted(() => {