mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
fix chat scroll and role section (#972)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bdf23d2b5d
commit
7a9b155db3
2 changed files with 58 additions and 10 deletions
|
|
@ -248,6 +248,11 @@ export function ChatSidebar({
|
|||
id: string
|
||||
messages: UIMessage[]
|
||||
} | null>(null)
|
||||
const [loadedThreadScrollTarget, setLoadedThreadScrollTarget] = useState<{
|
||||
id: string
|
||||
messageCount: number
|
||||
lastMessageId: string | null
|
||||
} | null>(null)
|
||||
|
||||
// Adjust chat height based on scroll position (desktop only, grid mode only)
|
||||
useEffect(() => {
|
||||
|
|
@ -298,6 +303,13 @@ export function ChatSidebar({
|
|||
useEffect(() => {
|
||||
if (pendingThreadLoad && currentChatId === pendingThreadLoad.id) {
|
||||
setMessages(pendingThreadLoad.messages)
|
||||
setLoadedThreadScrollTarget({
|
||||
id: pendingThreadLoad.id,
|
||||
messageCount: pendingThreadLoad.messages.length,
|
||||
lastMessageId:
|
||||
pendingThreadLoad.messages[pendingThreadLoad.messages.length - 1]
|
||||
?.id ?? null,
|
||||
})
|
||||
setPendingThreadLoad(null)
|
||||
}
|
||||
}, [currentChatId, pendingThreadLoad, setMessages])
|
||||
|
|
@ -653,15 +665,39 @@ export function ChatSidebar({
|
|||
}
|
||||
}, [queuedMessage])
|
||||
|
||||
// Scroll to bottom when a new user message is added
|
||||
// Scroll to bottom when a new user message is added or a thread is loaded
|
||||
useEffect(() => {
|
||||
const lastMessageId = messages[messages.length - 1]?.id ?? null
|
||||
const loadedThreadIsRendered =
|
||||
loadedThreadScrollTarget &&
|
||||
currentChatId === loadedThreadScrollTarget.id &&
|
||||
messages.length === loadedThreadScrollTarget.messageCount &&
|
||||
lastMessageId === loadedThreadScrollTarget.lastMessageId
|
||||
|
||||
if (loadedThreadIsRendered) {
|
||||
// Trigger the same scroll behavior as the button after loaded messages render.
|
||||
scrollToBottom()
|
||||
setTimeout(scrollToBottom, 50)
|
||||
setTimeout(scrollToBottom, 150)
|
||||
setTimeout(() => {
|
||||
scrollToBottom()
|
||||
setLoadedThreadScrollTarget(null)
|
||||
}, 300)
|
||||
return
|
||||
}
|
||||
const lastMessage = messages[messages.length - 1]
|
||||
if (lastMessage?.role === "user" && messagesContainerRef.current) {
|
||||
scrollToBottom()
|
||||
} else {
|
||||
checkIfScrolledToBottom()
|
||||
}
|
||||
}, [messages, checkIfScrolledToBottom, scrollToBottom])
|
||||
}, [
|
||||
currentChatId,
|
||||
loadedThreadScrollTarget,
|
||||
messages,
|
||||
checkIfScrolledToBottom,
|
||||
scrollToBottom,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
const isStreaming = status === "streaming"
|
||||
|
|
|
|||
|
|
@ -268,6 +268,22 @@ const PROFESSION_LABELS: {
|
|||
{ value: "medical", label: "Medical" },
|
||||
]
|
||||
|
||||
function getChangeProfessionPrompt(profession: Profession): string {
|
||||
const prompts: Record<Exclude<Profession, "default">, string> = {
|
||||
developer: "Not a developer?",
|
||||
research: "Not a researcher?",
|
||||
finance: "Not in finance?",
|
||||
design: "Not a designer?",
|
||||
legal: "Not in the legal field?",
|
||||
marketing: "Not in marketing?",
|
||||
medical: "Not in healthcare?",
|
||||
}
|
||||
if (profession === "default") {
|
||||
return "Not your role?"
|
||||
}
|
||||
return prompts[profession] ?? "Not your role?"
|
||||
}
|
||||
|
||||
// Static plugin metadata — shared between PluginPromoCard and RecommendedPluginsCard
|
||||
const PLUGIN_STATIC = [
|
||||
{
|
||||
|
|
@ -353,7 +369,7 @@ function RecommendedPluginsCard({
|
|||
return PLUGIN_STATIC.map((p) => ({
|
||||
...p,
|
||||
connected: connected[p.id] ?? false,
|
||||
onClick: onClicks[p.id]!,
|
||||
onClick: onClicks[p.id] ?? (() => {}),
|
||||
}))
|
||||
}, [hasMcp, connectedProviders, onOpenPlugins, onOpenIntegrations])
|
||||
|
||||
|
|
@ -446,11 +462,7 @@ function RecommendedPluginsCard({
|
|||
onClick={() => setIsEditing(true)}
|
||||
className="text-left px-2 pb-1 text-[10px] text-fg-faint hover:text-fg-muted transition-colors cursor-pointer"
|
||||
>
|
||||
Not a{" "}
|
||||
{PROFESSION_LABELS.find(
|
||||
(p) => p.value === profession,
|
||||
)?.label.toLowerCase()}
|
||||
? Change →
|
||||
{getChangeProfessionPrompt(profession)} Change role →
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -525,7 +537,7 @@ function PluginPromoCard({
|
|||
return PLUGIN_STATIC.map((p) => ({
|
||||
...p,
|
||||
connected: connected[p.id] ?? false,
|
||||
onClick: onClicks[p.id]!,
|
||||
onClick: onClicks[p.id] ?? (() => {}),
|
||||
})).filter((p) => !p.connected)
|
||||
}, [hasMcp, connectedProviders, onOpenPlugins, onOpenIntegrations])
|
||||
|
||||
|
|
@ -628,7 +640,7 @@ export function DashboardView({
|
|||
onOpenSearch,
|
||||
onOpenIntegrations,
|
||||
onOpenPlugins,
|
||||
onNavigateToMemories,
|
||||
onNavigateToMemories: _onNavigateToMemories,
|
||||
onNavigateToGraph,
|
||||
onOpenDocument,
|
||||
onHighlightsChat,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue