mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
🐛 fix(todo,matrix): improve click targets and type safety
- todo: Make task-content button fill full height for better click target - matrix: Fix TypeScript errors by using Boolean() for template expressions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bf0e788cba
commit
5b6f231e1a
2 changed files with 59 additions and 53 deletions
|
|
@ -2,7 +2,7 @@
|
|||
import { matrixStore, type SimpleMessage } from '$lib/matrix';
|
||||
import Message from './Message.svelte';
|
||||
import TypingIndicator from './TypingIndicator.svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { tick } from 'svelte';
|
||||
import { CircleNotch, ArrowDown } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -20,16 +20,46 @@
|
|||
let showScrollButton = $state(false);
|
||||
let loadingMore = $state(false);
|
||||
let prevMessageCount = $state(0);
|
||||
let hasInitiallyScrolled = $state(false);
|
||||
let currentRoomId = $state<string | null>(null);
|
||||
|
||||
// Auto-scroll to bottom on new messages (if already at bottom)
|
||||
// Reset state when room changes
|
||||
$effect(() => {
|
||||
const roomId = matrixStore.currentRoomId;
|
||||
if (roomId !== currentRoomId) {
|
||||
currentRoomId = roomId;
|
||||
hasInitiallyScrolled = false;
|
||||
prevMessageCount = 0;
|
||||
loadingMore = false;
|
||||
showScrollButton = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Initial scroll to bottom when messages first load, and auto-scroll on new messages
|
||||
$effect(() => {
|
||||
const messageCount = matrixStore.messages.length;
|
||||
if (messageCount > prevMessageCount && container) {
|
||||
|
||||
// Initial scroll when messages first appear for this room
|
||||
if (messageCount > 0 && !hasInitiallyScrolled && container) {
|
||||
tick().then(() => {
|
||||
if (container) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
hasInitiallyScrolled = true;
|
||||
prevMessageCount = messageCount;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-scroll on new messages (if already at bottom)
|
||||
if (messageCount > prevMessageCount && container && hasInitiallyScrolled) {
|
||||
const isAtBottom =
|
||||
container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
||||
if (isAtBottom) {
|
||||
tick().then(() => {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
if (container) {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -44,8 +74,13 @@
|
|||
container.scrollHeight - container.scrollTop - container.clientHeight;
|
||||
showScrollButton = distanceFromBottom > 200;
|
||||
|
||||
// Load more when scrolled to top
|
||||
if (container.scrollTop < 100 && !loadingMore) {
|
||||
// Load more when scrolled to top (only after initial scroll and with messages present)
|
||||
if (
|
||||
container.scrollTop < 100 &&
|
||||
!loadingMore &&
|
||||
hasInitiallyScrolled &&
|
||||
matrixStore.messages.length > 0
|
||||
) {
|
||||
loadMore();
|
||||
}
|
||||
}
|
||||
|
|
@ -59,10 +94,11 @@
|
|||
await matrixStore.loadMoreMessages(50);
|
||||
|
||||
// Maintain scroll position after loading
|
||||
tick().then(() => {
|
||||
await tick();
|
||||
if (container) {
|
||||
const newScrollHeight = container.scrollHeight;
|
||||
container.scrollTop = newScrollHeight - prevScrollHeight;
|
||||
});
|
||||
}
|
||||
|
||||
loadingMore = false;
|
||||
}
|
||||
|
|
@ -70,13 +106,6 @@
|
|||
function scrollToBottom() {
|
||||
container?.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Scroll to bottom on mount
|
||||
if (container) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="relative flex-1 min-h-0 overflow-hidden">
|
||||
|
|
@ -93,16 +122,24 @@
|
|||
{/if}
|
||||
|
||||
<!-- Messages -->
|
||||
<div class="space-y-1">
|
||||
<div class="space-y-0">
|
||||
{#each matrixStore.messages as message, index (message.id)}
|
||||
{@const prevMessage = matrixStore.messages[index - 1]}
|
||||
{@const showAvatar = !prevMessage || prevMessage.sender !== message.sender}
|
||||
{@const showTimestamp =
|
||||
!prevMessage || message.timestamp - prevMessage.timestamp > 5 * 60 * 1000}
|
||||
{@const nextMessage = matrixStore.messages[index + 1]}
|
||||
{@const isSameSender = Boolean(prevMessage && prevMessage.sender === message.sender)}
|
||||
{@const isNextSameSender = Boolean(nextMessage && nextMessage.sender === message.sender)}
|
||||
{@const prevDate = prevMessage ? new Date(prevMessage.timestamp).toDateString() : null}
|
||||
{@const currentDate = new Date(message.timestamp).toDateString()}
|
||||
{@const nextDate = nextMessage ? new Date(nextMessage.timestamp).toDateString() : null}
|
||||
{@const showDateSeparator = Boolean(prevMessage && prevDate !== currentDate)}
|
||||
{@const showAvatar = !isSameSender || showDateSeparator}
|
||||
{@const isLastInGroup = !isNextSameSender || Boolean(nextDate && nextDate !== currentDate)}
|
||||
<Message
|
||||
{message}
|
||||
{showAvatar}
|
||||
{showTimestamp}
|
||||
showTimestamp={showDateSeparator}
|
||||
{isSameSender}
|
||||
{isLastInGroup}
|
||||
showEncryptionBadge={isRoomEncrypted}
|
||||
{onReply}
|
||||
{onEdit}
|
||||
|
|
|
|||
|
|
@ -589,39 +589,6 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
/* DEBUG BORDERS - REMOVE AFTER DEBUGGING */
|
||||
.task-item-wrapper {
|
||||
outline: 2px dashed red !important;
|
||||
}
|
||||
.task-item {
|
||||
outline: 2px solid blue !important;
|
||||
}
|
||||
.drag-handle {
|
||||
outline: 2px solid green !important;
|
||||
}
|
||||
.task-checkbox {
|
||||
outline: 2px solid orange !important;
|
||||
}
|
||||
.task-content {
|
||||
outline: 2px solid purple !important;
|
||||
}
|
||||
.expand-btn {
|
||||
outline: 2px solid cyan !important;
|
||||
}
|
||||
.priority-dot {
|
||||
outline: 1px solid yellow !important;
|
||||
}
|
||||
.contacts-display {
|
||||
outline: 1px solid pink !important;
|
||||
}
|
||||
.due-date {
|
||||
outline: 1px solid lime !important;
|
||||
}
|
||||
.project-dot {
|
||||
outline: 1px solid magenta !important;
|
||||
}
|
||||
/* END DEBUG BORDERS */
|
||||
|
||||
/* Wrapper for expanded state */
|
||||
.task-item-wrapper {
|
||||
margin-bottom: 0;
|
||||
|
|
@ -839,12 +806,14 @@
|
|||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue