Source pages allow linking to messages

This commit is contained in:
thepaperpilot 2024-05-27 11:22:12 -05:00
parent d74e285447
commit 9165b6ea4a
4 changed files with 40 additions and 10 deletions

View file

@ -8,17 +8,18 @@
<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'" @mousedown="start(i)" @mouseup="stop" @contextmenu="e => openmenu(e, i)"> <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'" @mousedown="start(i)" @mouseup="stop" @contextmenu="e => openmenu(e, i)">
<Avatar v-if="event.contact !== sourceObj.selfContact" 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"> <div class="flex flex-col">
<span :class="getRoundedCornersClasses(threadItem, sourceObj.selfContact, i) + <span
' message px-2 py-1 flex items-center rounded-2xl' + :class="getClasses(i) + (event.contact === sourceObj.selfContact ? ' ml-13' : ' ml-2')"
(event.contact === sourceObj.selfContact ? ' ml-13' : ' ml-2')"> :ref="i === highlighted ? 'highlightedEvent' : undefined">
<component :is="parseMessage(threadItem, i)" /> <component :is="parseMessage(threadItem, i)" />
</span> </span>
<span v-if="event.contact !== sourceObj.selfContact" class="author px-2 text-sm italic mx-2">{{ sourceObj.contacts[event.contact].name }}</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> </div>
<div v-else class="flex mb-px" :class="event.contact === sourceObj.selfContact ? 'self self-end flex-row-reverse' : 'other self-start text-gray-200'" @mousedown="start(i)" @mouseup="stop" @contextmenu="e => openmenu(e, i)"> <div v-else class="flex mb-px" :class="event.contact === sourceObj.selfContact ? 'self self-end flex-row-reverse' : 'other self-start text-gray-200'" @mousedown="start(i)" @mouseup="stop" @contextmenu="e => openmenu(e, i)">
<span :class="getRoundedCornersClasses(threadItem, sourceObj.selfContact, i) + <span
' message px-2 py-1 flex items-center rounded-2xl ml-13'"> :class="getClasses(i) + ' ml-13'"
:ref="i === highlighted ? 'highlightedEvent' : undefined">
<component :is="parseMessage(threadItem, i)" /> <component :is="parseMessage(threadItem, i)" />
</span> </span>
</div> </div>
@ -54,6 +55,7 @@ const props = defineProps<{
sourceItem: number; sourceItem: number;
thread: number; thread: number;
baseUrl: string; baseUrl: string;
highlighted?: number;
}>(); }>();
const sourceObj = computed(() => sources.value[props.source]); const sourceObj = computed(() => sources.value[props.source]);
@ -62,12 +64,28 @@ const threadItem = computed(() => item.value.threads[props.thread]);
const message = ref(""); const message = ref("");
const messageInput = ref(); const messageInput = ref();
const highlightedEvent = ref();
function sendMessage() { function getClasses(index: number) {
let classes = 'message px-2 py-1 flex items-center rounded-2xl';
classes += ' ' + getRoundedCornersClasses(threadItem.value, sourceObj.value.selfContact, index);
if (props.highlighted === index) {
classes += ' animate-ping highlight';
}
return classes;
}
watch(highlightedEvent, element => {
element[0]?.scrollIntoView();
})
function sendMessage(e: Event) {
if (message.value.trim() === "") { if (message.value.trim() === "") {
return; return;
} }
e.preventDefault();
threadItem.value.timeline.push({ threadItem.value.timeline.push({
type: "message", type: "message",
contact: sourceObj.value.selfContact, contact: sourceObj.value.selfContact,
@ -245,4 +263,9 @@ function createToDo(event: number) {
.mr-13 { .mr-13 {
margin-right: 3.25rem; margin-right: 3.25rem;
} }
.highlight {
animation-delay: .5s;
animation-iteration-count: 1;
}
</style> </style>

View file

@ -12,11 +12,13 @@
</div> </div>
<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'"> <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" :isRead="isRead" @toggleRead="toggleRead" /> <PanelTitle :title="threadTitle" :isRead="isRead" @toggleRead="toggleRead" />
<Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" :base-url="baseUrl" /> <Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" :base-url="baseUrl" :highlighted="highlightedEvent" />
</div> </div>
<Modal :model-value="showThread" class="block xl:hidden" @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:header><div class="text-3xl">{{ threadTitle }}</div></template>
<template v-slot:body><Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" :base-url="baseUrl" /></template> <template v-slot:body>
<Thread :source="selectedItem?.source ?? 0" :sourceItem="selectedItem?.sourceItem ?? 0" :thread="selectedItem?.thread ?? 0" :base-url="baseUrl" :highlighted="highlightedEvent" />
</template>
</Modal> </Modal>
<SnoozeModal :snoozing="snoozing" :threadRef="snoozingItem" @close="stopSnoozing" /> <SnoozeModal :snoozing="snoozing" :threadRef="snoozingItem" @close="stopSnoozing" />
</div> </div>
@ -37,6 +39,11 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
const baseUrl = computed(() => `/source/${route.params.source}`); const baseUrl = computed(() => `/source/${route.params.source}`);
const highlightedEvent = computed(() => {
let event = route.params.event;
event = Array.isArray(event) ? event[0] : event;
return event ? parseInt(event) : undefined;
});
const sourceId = computed(() => parseInt(deArray(route.params.source))); const sourceId = computed(() => parseInt(deArray(route.params.source)));
const source = computed(() => sources.value[sourceId.value]); const source = computed(() => sources.value[sourceId.value]);

View file

@ -14,7 +14,7 @@ const routes: RouteRecordRaw[] = [
{ path: '/todo/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Todo, name: 'todo' }, { path: '/todo/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Todo, name: 'todo' },
{ path: '/snoozed/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Snoozed, name: 'snoozed' }, { path: '/snoozed/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Snoozed, name: 'snoozed' },
{ path: '/low/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: LowPriority, name: 'low' }, { path: '/low/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: LowPriority, name: 'low' },
{ path: '/source/:source(\\d+)/:sourceItem(\\d+)?/:thread(\\d+)?', component: Source, name: 'source' }, { path: '/source/:source(\\d+)/:sourceItem(\\d+)?/:thread(\\d+)?/:event(\\d+)?', component: Source, name: 'source' },
{ path: '/unsorted/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Unsorted, name: 'unsorted' }, { path: '/unsorted/:source(\\d+)?/:sourceItem(\\d+)?/:thread(\\d+)?', component: Unsorted, name: 'unsorted' },
]; ];

View file

@ -193,7 +193,7 @@ export function parseString(message: string) {
if (referencedMessage.type === "message") { if (referencedMessage.type === "message") {
parts.push(<span class="px-2 bg-emerald-200/25 rounded-2xl"> parts.push(<span class="px-2 bg-emerald-200/25 rounded-2xl">
{ referencedMessage.message } { referencedMessage.message }
<RouterLink class="text-slate-600 pl-2 text-sm" to={`/source/${sourceId}/${sourceItemId}/${threadId}`}> <RouterLink class="text-slate-600 pl-2 text-sm" to={`/source/${sourceId}/${sourceItemId}/${threadId}/${messageId}`}>
goto message goto message
</RouterLink> </RouterLink>
</span>); </span>);