From 253a82bdb757fdaa45c7705880f3c85ebdd8b686 Mon Sep 17 00:00:00 2001 From: "vorflux[bot]" <249966464+vorflux[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 19:10:43 -0700 Subject: [PATCH] fix: add show more/less toggle for truncated highlights in Nova (#1029) Co-authored-by: Vorflux AI --- apps/web/components/chat/index.tsx | 15 ++++++++-- apps/web/components/highlights-card.tsx | 40 +++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index af21ddfad..d140b469e 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -364,12 +364,23 @@ export function ChatSidebar({ ) const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter" && !e.shiftKey) { + if (e.key === "Enter" && !e.shiftKey && !isMobile) { e.preventDefault() handleSend() } } + // When the user stops generation before any assistant response arrives, + // remove the dangling user message so it isn't duplicated on the next send. + const handleStop = useCallback(() => { + stop() + setMessages((prev) => { + const last = prev[prev.length - 1] + if (last?.role === "user") return prev.slice(0, -1) + return prev + }) + }, [stop, setMessages]) + const handleCopyMessage = useCallback((messageId: string, text: string) => { analytics.chatMessageCopied({ message_id: messageId }) navigator.clipboard.writeText(text) @@ -1137,7 +1148,7 @@ export function ChatSidebar({ value={input} onChange={(e) => setInput(e.target.value)} onSend={handleSend} - onStop={stop} + onStop={handleStop} onKeyDown={handleKeyDown} isResponding={isResponding} activeStatus={ diff --git a/apps/web/components/highlights-card.tsx b/apps/web/components/highlights-card.tsx index 813004352..38257d2e2 100644 --- a/apps/web/components/highlights-card.tsx +++ b/apps/web/components/highlights-card.tsx @@ -1,6 +1,12 @@ "use client" -import { useState, useCallback, useRef, useEffect } from "react" +import { + useState, + useCallback, + useRef, + useEffect, + useLayoutEffect, +} from "react" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" import { @@ -75,6 +81,9 @@ export function HighlightsCard({ const [activeIndex, setActiveIndex] = useState(0) const [isReplyOpen, setIsReplyOpen] = useState(false) const [replyText, setReplyText] = useState("") + const [isExpanded, setIsExpanded] = useState(false) + const [isClamped, setIsClamped] = useState(false) + const contentRef = useRef(null) const replyInputRef = useRef(null) const currentItem = items[activeIndex] @@ -87,18 +96,28 @@ export function HighlightsCard({ useEffect(() => { setIsReplyOpen(false) setReplyText("") + setIsExpanded(false) }, [items]) + // biome-ignore lint/correctness/useExhaustiveDependencies: re-run when item or expansion changes to detect clamping + useLayoutEffect(() => { + const el = contentRef.current + if (!el) return + setIsClamped(el.scrollHeight > el.clientHeight) + }, [currentItem, isExpanded]) + const handlePrev = useCallback(() => { setActiveIndex((prev) => (prev > 0 ? prev - 1 : items.length - 1)) setIsReplyOpen(false) setReplyText("") + setIsExpanded(false) }, [items.length]) const handleNext = useCallback(() => { setActiveIndex((prev) => (prev < items.length - 1 ? prev + 1 : 0)) setIsReplyOpen(false) setReplyText("") + setIsExpanded(false) }, [items.length]) const handleChatClick = useCallback(() => { @@ -259,12 +278,27 @@ export function HighlightsCard({
-

+

{currentItem.title}

-
+
{renderContent(currentItem.content, currentItem.format)}
+ {(isClamped || isExpanded) && ( + + )}
{isReplyOpen && (