unify card/modal
This commit is contained in:
@@ -5,7 +5,7 @@ import { ChatMessages } from './ChatMessages.js';
|
||||
import { QuestionBlock } from './QuestionBlock.js';
|
||||
import { SimpleInput } from './SimpleInput.js';
|
||||
|
||||
export function SessionCard({ session, onClick, conversation, onFetchConversation, onRespond, onDismiss }) {
|
||||
export function SessionCard({ session, onClick, conversation, onFetchConversation, onRespond, onDismiss, enlarged = false }) {
|
||||
const hasQuestions = session.pending_questions && session.pending_questions.length > 0;
|
||||
const statusMeta = getStatusMeta(session.status);
|
||||
const agent = session.agent === 'codex' ? 'codex' : 'claude';
|
||||
@@ -20,23 +20,51 @@ export function SessionCard({ session, onClick, conversation, onFetchConversatio
|
||||
}, [session.session_id, session.project_dir, agent, conversation, onFetchConversation]);
|
||||
|
||||
const chatPaneRef = useRef(null);
|
||||
const wasAtBottomRef = useRef(true);
|
||||
const prevConversationLenRef = useRef(0);
|
||||
|
||||
// Scroll chat pane to bottom when conversation loads or updates
|
||||
// Track scroll position for smart scrolling
|
||||
useEffect(() => {
|
||||
const el = chatPaneRef.current;
|
||||
if (el) el.scrollTop = el.scrollHeight;
|
||||
if (!el) return;
|
||||
|
||||
const handleScroll = () => {
|
||||
const threshold = 50;
|
||||
wasAtBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
|
||||
};
|
||||
|
||||
el.addEventListener('scroll', handleScroll);
|
||||
return () => el.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
// Smart scroll: only scroll to bottom on new messages if user was already at bottom
|
||||
useEffect(() => {
|
||||
const el = chatPaneRef.current;
|
||||
if (!el || !conversation) return;
|
||||
|
||||
const hasNewMessages = conversation.length > prevConversationLenRef.current;
|
||||
prevConversationLenRef.current = conversation.length;
|
||||
|
||||
if (hasNewMessages && wasAtBottomRef.current) {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
}, [conversation]);
|
||||
|
||||
const handleDismissClick = (e) => {
|
||||
e.stopPropagation();
|
||||
onDismiss(session.session_id);
|
||||
if (onDismiss) onDismiss(session.session_id);
|
||||
};
|
||||
|
||||
// Container classes differ based on enlarged mode
|
||||
const containerClasses = enlarged
|
||||
? 'glass-panel flex w-full max-w-[90vw] max-h-[90vh] flex-col overflow-hidden rounded-2xl border border-selection/80'
|
||||
: 'glass-panel flex h-[850px] max-h-[850px] w-[600px] cursor-pointer flex-col overflow-hidden rounded-xl border border-selection/70 transition-[border-color,box-shadow] duration-200 hover:border-starting/35 hover:shadow-panel';
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="glass-panel flex h-[850px] max-h-[850px] w-[600px] cursor-pointer flex-col overflow-hidden rounded-xl border border-selection/70 transition-[border-color,box-shadow] duration-200 hover:border-starting/35 hover:shadow-panel"
|
||||
class=${containerClasses}
|
||||
style=${{ borderLeftWidth: '3px', borderLeftColor: statusMeta.borderColor }}
|
||||
onClick=${() => onClick(session)}
|
||||
onClick=${enlarged ? undefined : () => onClick && onClick(session)}
|
||||
>
|
||||
<!-- Card Header -->
|
||||
<div class="shrink-0 border-b px-4 py-3 ${agentHeaderClass}">
|
||||
@@ -86,7 +114,7 @@ export function SessionCard({ session, onClick, conversation, onFetchConversatio
|
||||
|
||||
<!-- Card Content Area (Chat) -->
|
||||
<div ref=${chatPaneRef} class="flex-1 min-h-0 overflow-y-auto bg-surface px-4 py-4">
|
||||
<${ChatMessages} messages=${conversation || []} status=${session.status} />
|
||||
<${ChatMessages} messages=${conversation || []} status=${session.status} limit=${enlarged ? null : 20} />
|
||||
</div>
|
||||
|
||||
<!-- Card Footer (Input or Questions) -->
|
||||
|
||||
Reference in New Issue
Block a user