Sending messages and styling pass
This commit is contained in:
parent
a8e3eaea46
commit
5635b12ca4
8 changed files with 162 additions and 66 deletions
|
@ -1,13 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import Nav from './components/Nav.vue'
|
||||
import { useRoute, RouterView } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
import { RouterView } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Nav />
|
||||
<div class="p-4 md:ml-64 min-h-screen">
|
||||
<div class="md:ml-64 h-screen overflow-hidden">
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<template>
|
||||
<div v-if="Object.keys(sourceItem.threads).length === 1 && '0' in sourceItem.threads"
|
||||
class="p-4 border-2 -mt-2px cursor-pointer bg-gray-200 border-gray-800" :class="isSelected(0) ? 'selected shadow-md scale-105' : ''" @click="emits('select', 0)">
|
||||
<div class="flex">
|
||||
<Avatar v-if="contact" v-bind="contact" class="mr-2" />
|
||||
<span class="grow">{{ item.threads[0].preview }}</span>
|
||||
<div class="flex items-center">
|
||||
<Avatar v-if="getContact(0)" v-bind="getContact(0)!" class="mr-2" />
|
||||
<span class="bg-gray-300 px-2 py-1 rounded-2xl block overflow-hidden text-nowrap text-ellipsis">{{ item.threads[0].preview }}</span>
|
||||
<span class="grow" />
|
||||
<span v-if="item.threads[0].count > 1" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium text-blue-800 bg-blue-100 rounded-full dark:bg-blue-900 dark:text-blue-300">{{ item.threads[0].count }}</span>
|
||||
</div>
|
||||
<div class="flex -mb-2 text-gray-500 text-sm font-normal">
|
||||
|
@ -18,10 +19,11 @@
|
|||
<span>{{ source.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(thread, id) in item.threads" class="p-4 border-2 -mt-2px cursor-pointer bg-slate-300 border-gray-800" :class="isSelected(id) ? 'selected shadow-md scale-105 thread' : ''" @click="emits('select', parseInt(id as unknown as string))">
|
||||
<div class="flex">
|
||||
<Avatar v-if="contact" v-bind="contact" class="mr-2" />
|
||||
<span class="grow">{{ thread.preview }}</span>
|
||||
<div v-for="(thread, id) in item.threads" class="p-4 border-2 -mt-2px cursor-pointer bg-slate-300 border-gray-800" :class="isSelected(id) ? 'selected shadow-md -mx-2 thread' : ''" @click="emits('select', parseInt(id as unknown as string))">
|
||||
<div class="flex items-center">
|
||||
<Avatar v-if="getContact(id)" v-bind="getContact(id)!" class="mr-2" />
|
||||
<span class="bg-gray-100 px-2 py-1 rounded-2xl block overflow-hidden text-nowrap text-ellipsis">{{ thread.preview }}</span>
|
||||
<span class="grow" />
|
||||
<span v-if="thread.count > 1" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium text-blue-800 bg-blue-100 rounded-full dark:bg-blue-900 dark:text-blue-300">{{ thread.count }}</span>
|
||||
</div>
|
||||
<div class="flex -mb-2 text-gray-500 text-sm font-normal">
|
||||
|
@ -48,7 +50,11 @@ const emits = defineEmits<{
|
|||
|
||||
const source = computed(() => sources.value[props.item.source]);
|
||||
const sourceItem = computed(() => source.value.items[props.item.sourceItem]);
|
||||
const contact = computed(() => props.item.threads[0].contact == null ? null : sources.value[props.item.source].contacts[props.item.threads[0].contact])
|
||||
|
||||
function getContact(thread: number) {
|
||||
const contact = props.item.threads[thread].contact;
|
||||
return contact == null ? undefined : sources.value[props.item.source].contacts[contact];
|
||||
}
|
||||
|
||||
function isSelected(thread: number | string) {
|
||||
if (typeof thread === "string") {
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
<div class="h-full px-3 py-4 overflow-y-auto bg-gray-50 dark:bg-gray-800 flex flex-col">
|
||||
<ul class="space-x-2 py-2 flex flex-row overflow-x-hidden hover:overflow-x-auto">
|
||||
<li v-for="contact in urgentContacts" class="shrink-0">
|
||||
<RouterLink :to="`source/${contact.source}/${contact.sourceItem}/${contact.thread}`" class="flex items-center text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group relative">
|
||||
<RouterLink :to="`source/${contact.source}/${contact.sourceItem}/${contact.thread}`" class="flex items-center text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group relative" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<Avatar :image="contact.image" :name="contact.name" :status="contact.status ?? 'unknown'" />
|
||||
<span class="absolute bg-gray-800 bottom-0 right-0 h-4 w-4 text-center rounded-full">{{ Math.min(contact.count, 9) }}</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li v-for="contact in pinned" class="shrink-0">
|
||||
<RouterLink :to="`source/${contact.source}/${contact.id}/${contact.thread}`" class="flex items-center text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group relative">
|
||||
<RouterLink :to="`source/${contact.source}/${contact.id}/${contact.thread}`" class="flex items-center text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group relative" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<Avatar :image="contact.image" :name="contact.name" :status="contact.status ?? 'unknown'" />
|
||||
<span v-if="contact.count > 0" class="absolute bg-gray-800 bottom-0 right-0 h-4 w-4 text-center rounded-full">{{ Math.min(contact.count, 9) }}</span>
|
||||
<FontAwesomeIcon v-else :icon="faThumbTack" class="star absolute drop-shadow-2xl bottom-0 right-0 h-4 w-4 text-center rounded-full" />
|
||||
|
@ -24,7 +24,7 @@
|
|||
<hr/>
|
||||
<ul class="space-y-2 font-medium pt-2">
|
||||
<li>
|
||||
<RouterLink to="/todo" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/todo" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700" :class="route.name === 'home' ? 'bg-gray-100 dark:bg-gray-700' : ''">
|
||||
<FontAwesomeIcon :icon="faListCheck" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">To Do</span>
|
||||
<span class="flex-grow" />
|
||||
|
@ -32,19 +32,19 @@
|
|||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/low" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/low" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faList" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">Low Priority</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/garden" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/garden" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faLeaf" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">Garden</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/me" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/me" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faFaceSmile" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">My messages</span>
|
||||
</RouterLink>
|
||||
|
@ -55,7 +55,7 @@
|
|||
<div>Sources</div>
|
||||
<ul class="space-y-2 p-2 text-sm">
|
||||
<li v-for="source in sources">
|
||||
<RouterLink :to="`/source/${source.id}`" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink :to="`/source/${source.id}`" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
{{ source.name }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
|
@ -67,19 +67,19 @@
|
|||
<ul class="space-y-2 font-medium">
|
||||
<li><hr/></li>
|
||||
<li>
|
||||
<RouterLink to="/snoozed" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/snoozed" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faClock" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">Snoozed</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/unsorted" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/unsorted" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faShuffle" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">Unsorted</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/settings" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||
<RouterLink to="/settings" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group" active-class="bg-gray-100 dark:bg-gray-700">
|
||||
<FontAwesomeIcon :icon="faGear" class="w-5 h-5 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white" />
|
||||
<span class="ms-3">Settings</span>
|
||||
</RouterLink>
|
||||
|
@ -94,11 +94,13 @@ import { faBars, faClock, faFaceSmile, faGear, faLeaf, faList, faListCheck, faSh
|
|||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
import { initFlowbite } from 'flowbite'
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
import type { ContactStatus } from "../state"
|
||||
import { categories, favorites, sources, todoItems, urgentItems } from '../state'
|
||||
import Avatar from "./Avatar.vue"
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
onMounted(() => {
|
||||
initFlowbite();
|
||||
});
|
||||
|
|
18
src/components/PanelTitle.vue
Normal file
18
src/components/PanelTitle.vue
Normal file
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<div class="text-3xl mb-4 shrink-0">{{ title }}</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
title: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div {
|
||||
width: calc((100vw - 23rem) / 2);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
|
@ -1,31 +1,31 @@
|
|||
<template>
|
||||
<div class="flex flex-col grow">
|
||||
<div class="flex flex-col grow shrink">
|
||||
<div class="flex flex-col grow shrink thread overflow-y-auto mb-4 -mr-4 pr-4">
|
||||
<template v-for="(event, i) in threadItem.timeline">
|
||||
<template v-if="event.type === 'message'">
|
||||
<div v-if="i === threadItem.timeline.length - 1 || threadItem.timeline[i + 1].type !== 'message' || threadItem.timeline[i + 1].contact !== event.contact" style="max-width: 80%;" class="flex mb-2" :class="event.contact === sourceObj.selfContact ? 'self self-end flex-row-reverse' : 'other self-start'">
|
||||
<Avatar v-bind="sourceObj.contacts[event.contact]" class="self-end" />
|
||||
<Avatar v-if="event.contact !== sourceObj.selfContact" v-bind="sourceObj.contacts[event.contact]" class="self-end" />
|
||||
<div class="flex flex-col">
|
||||
<span class="message mx-2 px-2 py-1 flex items-center rounded-full">{{ event.message }}</span>
|
||||
<span class="author px-2 text-sm italic mx-2">{{ sourceObj.contacts[event.contact].name }}</span>
|
||||
<span class="message px-2 py-1 flex items-center rounded-2xl" :class="getRoundedCornersClasses(i) + (event.contact === sourceObj.selfContact ? ' ml-13' : ' ml-2')">{{ event.message }}</span>
|
||||
<span v-if="event.contact !== sourceObj.selfContact" class="author px-2 text-sm italic mx-2">{{ sourceObj.contacts[event.contact].name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else style="max-width: 80%;" class="flex mb-2" :class="event.contact === sourceObj.selfContact ? 'self self-end flex-row-reverse' : 'other self-start text-gray-200'">
|
||||
<span class="message px-2 py-1 flex items-center rounded-full" :class="event.contact === sourceObj.selfContact ? 'mr-13' : 'ml-13'">{{ event.message }}</span>
|
||||
<div v-else style="max-width: 80%;" class="flex mb-px" :class="event.contact === sourceObj.selfContact ? 'self self-end flex-row-reverse' : 'other self-start text-gray-200'">
|
||||
<span class="message px-2 py-1 flex items-center rounded-2xl ml-13" :class="getRoundedCornersClasses(i)">{{ event.message }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else-if="event.type === 'create-thread'" class="self-center mb-2 italic text-gray-500">
|
||||
<div v-else-if="event.type === 'create-thread'" class="self-center mb-2 italic text-gray-500 text-center">
|
||||
{{ sourceObj.contacts[event.contact].name }} created a new thread called "<RouterLink :to="`${baseUrl}/${source}/${sourceItem}/${event.thread}`" class="text-blue-500">{{ item.threads[event.thread].title }}</RouterLink>"
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<input type="text" />
|
||||
</div>
|
||||
<form @submit="sendMessage" class="shrink-0">
|
||||
<input id="message_input" class="w-full" ref="messageInput" autofocus type="text" v-model="message" />
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { sources } from '../state';
|
||||
import { computed, ref } from 'vue';
|
||||
import { items, sources } from '../state';
|
||||
import Avatar from './Avatar.vue';
|
||||
import { RouterLink } from 'vue-router';
|
||||
|
||||
|
@ -39,9 +39,65 @@ const props = defineProps<{
|
|||
const sourceObj = computed(() => sources.value[props.source]);
|
||||
const item = computed(() => sourceObj.value.items[props.sourceItem]);
|
||||
const threadItem = computed(() => item.value.threads[props.thread]);
|
||||
|
||||
const message = ref("");
|
||||
const messageInput = ref();
|
||||
|
||||
function sendMessage() {
|
||||
if (message.value.trim() === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
threadItem.value.timeline.push({
|
||||
type: "message",
|
||||
contact: sourceObj.value.selfContact,
|
||||
message: message.value,
|
||||
time: Date.now()
|
||||
});
|
||||
|
||||
let item = items.value.find(item => item.source === props.source && item.sourceItem === props.sourceItem);
|
||||
if (item == null) {
|
||||
item = { source: props.source, sourceItem: props.sourceItem, threads: {}, updatedAt: Date.now() };
|
||||
items.value.push(item);
|
||||
}
|
||||
if (item.threads[props.thread] == null) {
|
||||
item.threads[props.thread] = {
|
||||
count: 1,
|
||||
preview: message.value,
|
||||
updatedAt: Date.now(),
|
||||
contact: sourceObj.value.selfContact
|
||||
}
|
||||
} else {
|
||||
item.threads[props.thread].count++;
|
||||
item.threads[props.thread].preview = message.value;
|
||||
item.threads[props.thread].updatedAt = Date.now();
|
||||
item.threads[props.thread].contact = sourceObj.value.selfContact;
|
||||
}
|
||||
|
||||
message.value = "";
|
||||
messageInput.value?.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
function getRoundedCornersClasses(index: number) {
|
||||
const contact = threadItem.value.timeline[index]?.contact;
|
||||
if (contact == null) {
|
||||
return "";
|
||||
}
|
||||
const side = contact === sourceObj.value.selfContact ? 'r' : 'l';
|
||||
let classes = `rounded-b${side}-none`;
|
||||
if (threadItem.value.timeline[index - 1] != null && threadItem.value.timeline[index - 1].type === 'message' && threadItem.value.timeline[index - 1].contact === contact) {
|
||||
classes += ` rounded-t${side}-none`;
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.thread > * {
|
||||
min-width: calc((100vw - 23rem) / 2);
|
||||
}
|
||||
|
||||
.other .message {
|
||||
background-color: gray;
|
||||
color: rgb(229 231 235);
|
||||
|
|
|
@ -1,45 +1,50 @@
|
|||
<template>
|
||||
<div class="flex gap-x-4">
|
||||
<div class="grow basis-6/12">
|
||||
<div class="flex h-full">
|
||||
<div class="grow basis-6/12 p-4 overflow-x-hidden">
|
||||
<div class="text-3xl mb-4">Todo</div>
|
||||
<div v-for="category in todoCategories">
|
||||
<CategoryHeader v-bind="category" />
|
||||
<ItemGroup :items="category.activeItems" :selected-thread="selectedItem" @select-item="selectItem" />
|
||||
<ItemGroup :items="category.activeItems" :selected-thread="showThread ? selectedItem : undefined" @select-item="selectItem" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden xl:flex grow basis-6/12 bg-slate-200 p-4 -m-4 ml-0 min-h-screen flex-col" v-if="selectedItem">
|
||||
<div class="text-3xl mb-4">{{ threadTitle }}</div>
|
||||
<Thread :source="selectedItem.source" :sourceItem="selectedItem.sourceItem" :thread="selectedItem.thread" base-url="/todo" />
|
||||
<div class="hidden xl:flex bg-slate-200 ml-0 h-screen flex-col overflow-hidden" :class="showThread ? 'p-4 basis-6/12' : 'basis-0'">
|
||||
<PanelTitle :title="threadTitle" />
|
||||
<Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" base-url="/todo" />
|
||||
</div>
|
||||
<Modal :model-value="true" class="block xl:hidden" v-if="selectedItem" @update:model-value="close">
|
||||
<Modal :model-value="showThread" class="block xl:hidden" @update:model-value="close">
|
||||
<template v-slot:header><div class="text-3xl">{{ threadTitle }}</div></template>
|
||||
<template v-slot:body><Thread :source="selectedItem.source" :sourceItem="selectedItem.sourceItem" :thread="selectedItem.thread" base-url="/todo" /></template>
|
||||
<template v-slot:body><Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" base-url="/todo" /></template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ThreadRef, sources, todoCategories } from '../state';
|
||||
import CategoryHeader from "./CategoryHeader.vue";
|
||||
import ItemGroup from "./ItemGroup.vue";
|
||||
import Modal from './Modal.vue';
|
||||
import PanelTitle from './PanelTitle.vue';
|
||||
import Thread from './Thread.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const selectedItem = computed<ThreadRef | undefined>(() => {
|
||||
const { source, sourceItem, thread } = route.params;
|
||||
const showThread = ref(false);
|
||||
const selectedItem = ref<ThreadRef | undefined>();
|
||||
watch([() => route.params.source, () => route.params.sourceItem, () => route.params.thread], ([source, sourceItem, thread]) => {
|
||||
const sourceInt = parseInt(Array.isArray(source) ? source[0] : source);
|
||||
const sourceItemInt = parseInt(Array.isArray(sourceItem) ? sourceItem[0] : sourceItem);
|
||||
const threadInt = parseInt(Array.isArray(thread) ? thread[0] : thread);
|
||||
if (!isNaN(sourceInt) && !isNaN(sourceItemInt) && !isNaN(threadInt)) {
|
||||
return { source: sourceInt, sourceItem: sourceItemInt, thread: threadInt };
|
||||
selectedItem.value = { source: sourceInt, sourceItem: sourceItemInt, thread: threadInt };
|
||||
showThread.value = true;
|
||||
} else {
|
||||
// Intentionally leave selectedItem so animations look right
|
||||
showThread.value = false;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}, { immediate: true });
|
||||
|
||||
const threadTitle = computed(() => {
|
||||
const selected = selectedItem.value;
|
||||
|
@ -50,18 +55,19 @@ const threadTitle = computed(() => {
|
|||
});
|
||||
|
||||
function selectItem(source: number, sourceItem: number, thread: number) {
|
||||
console.log("!!", selectedItem.value, source, sourceItem, thread)
|
||||
if (selectedItem.value != null) {
|
||||
const s = selectedItem.value;
|
||||
if (source === s.source && sourceItem === s.sourceItem && thread === s.thread) {
|
||||
const p = route.params;
|
||||
const sourceInt = parseInt(Array.isArray(p.source) ? p.source[0] : p.source);
|
||||
const sourceItemInt = parseInt(Array.isArray(p.sourceItem) ? p.sourceItem[0] : p.sourceItem);
|
||||
const threadInt = parseInt(Array.isArray(p.thread) ? p.thread[0] : p.thread);
|
||||
if (source === sourceInt && sourceItem === sourceItemInt && thread === threadInt) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
router.push(`/todo/${source}/${sourceItem}/${thread}`);
|
||||
}
|
||||
|
||||
function close() {
|
||||
console.log("closing thread")
|
||||
router.push("/todo");
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -6,8 +6,8 @@ import App from "./App.vue";
|
|||
import Todo from "./components/Todo.vue";
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{ path: '/', component: Todo },
|
||||
{ path: '/todo/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Todo },
|
||||
{ path: '/', component: Todo, name: 'home' },
|
||||
{ path: '/todo/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Todo, name: 'todo' },
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
@ -16,3 +16,7 @@ const router = createRouter({
|
|||
});
|
||||
|
||||
createApp(App).use(router).mount("#app");
|
||||
|
||||
document.onkeypress = function() {
|
||||
document.getElementById("message_input")?.focus();
|
||||
};
|
||||
|
|
|
@ -12,4 +12,10 @@ export default {
|
|||
require('flowbite/plugin')
|
||||
],
|
||||
darkMode: 'selector',
|
||||
safelist: [
|
||||
'rounded-tr-none',
|
||||
'rounded-tl-none',
|
||||
'rounded-br-none',
|
||||
'rounded-bl-none'
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue