feat: reply + search + forward + archive/mute + error boundary
Messages: - Reply-to: hover action, composer chip with cancel, quote bubble inside the replying message with tap-to-jump + amber highlight ring - Search: header search button toggles in-conversation search bar with prev/next + match counter, auto-jump to active match - Forward: multi-select conversation picker. Attachments are now carried over: download + decrypt source, re-encrypt under each target conv-key, re-upload with fresh per-attachment keys, insert new attachment rows Conversations: - Archive + mute per member. New migration 20260420000001 adds `archived` + `muted_until` on conversation_members. Shared helpers: setConversationArchived / setConversationMutedUntil / isConversationMuted - ChatsPage: archive toggle in header with unread badge for archived bucket, split active/archived lists, muted indicator (BellOff icon, dimmed unread badge) - ConversationRowMenu via createPortal (escapes sidebar overflow clip), forwardRef-based MenuItem so submenu positioning refs survive React 18 - ConversationsContext: suppresses notification sound + OS notif when target conversation is muted - Refresh on `profiles UPDATE` realtime so peer avatar / displayName changes flow to conversation.members without manual refresh Resilience: - ErrorBoundary (Discord-style): centred spinner + escalating copy, no manual reload button. Backoff retry schedule [2s, 4s, 8s, 15s, 30s]. Uses a keyed Fragment (not a div wrapper) so flex h-full chains survive - App wrapped root + per-route RouteBoundary, conversation-level boundary - AuthContext: flip `ready` immediately on cached session read; validate getUser in background so a stalled/offline Supabase doesn't freeze the app on the loading spinner Crypto: - Swap libsodium-wrappers -> libsodium-wrappers-sumo (compact build was missing crypto_pwhash so Argon2id vault KDF threw, falling back to plaintext localStorage on every launch) - Shim d.ts for sumo types (sumo is API superset, no official types ship) - vite optimizeDeps includes sumo with the "require" condition - secureFileStore: exists(dir) check before mkdir; surface genuine permission errors instead of silent catch Tauri: - fs scope adds `$APPLOCALDATA` direct entry (not just /**) so the app data directory itself can be mkdir'd on first launch Chat layout: - Skip call_event messages when computing avatar run boundaries so a regular bubble followed by a call event from the same sender still shows its avatar
This commit is contained in:
@@ -409,6 +409,74 @@ export function SendIcon(props: IconProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export function ArchiveIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<rect x="3" y="4" width="18" height="5" rx="1" />
|
||||
<path d="M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9" />
|
||||
<path d="M10 13h4" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function BellIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<path d="M6 8a6 6 0 1 1 12 0c0 4 1.5 5 2 6H4c.5-1 2-2 2-6Z" />
|
||||
<path d="M9.5 18a2.5 2.5 0 0 0 5 0" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function BellOffIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<path d="M9.5 18a2.5 2.5 0 0 0 5 0" />
|
||||
<path d="M13.73 4A2 2 0 0 0 10 4" />
|
||||
<path d="M18 8c0 1-.1 1.9-.2 2.7" />
|
||||
<path d="M4 4 20 20" />
|
||||
<path d="M6 8a6 6 0 0 1 .2-1.7" />
|
||||
<path d="M4 18h13.5L18 17.4c.5-1 2-2 2-6" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function MoreVerticalIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<circle cx="12" cy="5" r="1.5" />
|
||||
<circle cx="12" cy="12" r="1.5" />
|
||||
<circle cx="12" cy="19" r="1.5" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function ReplyIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<polyline points="9 17 4 12 9 7" />
|
||||
<path d="M20 18v-2a4 4 0 0 0-4-4H4" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function ForwardIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<polyline points="15 17 20 12 15 7" />
|
||||
<path d="M4 18v-2a4 4 0 0 1 4-4h12" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function ChevronUpIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
<polyline points="18 15 12 9 6 15" />
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
export function AddUserIcon(props: IconProps) {
|
||||
return (
|
||||
<Base {...props}>
|
||||
|
||||
Reference in New Issue
Block a user