fix(web): unify mic/send button and restore scroll-down
Some checks failed
CI / test (push) Failing after 20s
Some checks failed
CI / test (push) Failing after 20s
- show one action button in composer: mic when empty, send when text exists - add floating scroll-to-bottom button in message list - exclude non-text/media messages from Chat Info links list to avoid duplicates
This commit is contained in:
@@ -67,6 +67,8 @@ export function MessageList() {
|
||||
const [undoTick, setUndoTick] = useState(0);
|
||||
const [reactionsByMessage, setReactionsByMessage] = useState<Record<number, MessageReaction[]>>({});
|
||||
const [mediaViewer, setMediaViewer] = useState<MediaViewerState>(null);
|
||||
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
|
||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const messages = useMemo(() => {
|
||||
if (!activeChatId) {
|
||||
@@ -143,11 +145,28 @@ export function MessageList() {
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [activeChatId, focusedMessageId, messages.length, setFocusedMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = scrollContainerRef.current;
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const distance = container.scrollHeight - container.scrollTop - container.clientHeight;
|
||||
setShowScrollToBottom(distance > 180);
|
||||
}, [messages.length, activeChatId]);
|
||||
|
||||
if (!activeChatId) {
|
||||
return <div className="flex h-full items-center justify-center text-slate-300/80">Select a chat</div>;
|
||||
}
|
||||
const chatId = activeChatId;
|
||||
|
||||
function scrollToBottom() {
|
||||
const container = scrollContainerRef.current;
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: "smooth" });
|
||||
}
|
||||
|
||||
async function ensureReactionsLoaded(messageId: number) {
|
||||
if (reactionsByMessage[messageId]) {
|
||||
return;
|
||||
@@ -325,7 +344,15 @@ export function MessageList() {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="tg-scrollbar flex-1 overflow-auto px-2 py-4 md:px-5">
|
||||
<div
|
||||
className="tg-scrollbar flex-1 overflow-auto px-2 py-4 md:px-5"
|
||||
ref={scrollContainerRef}
|
||||
onScroll={(event) => {
|
||||
const target = event.currentTarget;
|
||||
const distance = target.scrollHeight - target.scrollTop - target.clientHeight;
|
||||
setShowScrollToBottom(distance > 180);
|
||||
}}
|
||||
>
|
||||
{hasMore ? (
|
||||
<div className="mb-3 flex justify-center">
|
||||
<button
|
||||
@@ -466,6 +493,17 @@ export function MessageList() {
|
||||
</div>
|
||||
|
||||
<div className="px-5 pb-2 text-xs text-slate-300/80">{(typingByChat[activeChatId] ?? []).length > 0 ? "typing..." : ""}</div>
|
||||
{showScrollToBottom ? (
|
||||
<div className="pointer-events-none absolute bottom-4 right-4 z-40">
|
||||
<button
|
||||
className="pointer-events-auto inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-600/80 bg-slate-900/90 text-lg text-slate-100 shadow-lg hover:bg-slate-800"
|
||||
onClick={scrollToBottom}
|
||||
type="button"
|
||||
>
|
||||
↓
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{ctx
|
||||
? createPortal(
|
||||
|
||||
Reference in New Issue
Block a user