Add user‑message collapse/expand feature
Implemented a per‑message collapse state that hides long user messages (>30 lines) with a “Show entire message / Collapse” button. • Added collapsedUserMsgs map and helper collapseKeyFor to generate stable keys. • Initialized or updated the collapse map whenever chat sessions or the active session change, preserving user toggles. • Provided toggleUserMsgCollapse to switch the collapsed state. • Updated the JSX to render the truncated content with an ellipsis when collapsed and render the expand/collapse button. • Adjusted CSS for the new expand button: changed color to var(--muted), added align-self: flex-start, removed stray left margin, and retained bold, pointer cursor, and left‑aligned text. • Minor style tweaks for the button hover effect.
This commit is contained in:
58
src/App.jsx
58
src/App.jsx
@@ -352,6 +352,38 @@ export default function App() {
|
||||
// Tip state: { [sessionId]: messageId }
|
||||
const [newMsgTip, setNewMsgTip] = useState({});
|
||||
|
||||
// Collapse state per user message: { [msgKey]: boolean } — true means "collapsed"
|
||||
const [collapsedUserMsgs, setCollapsedUserMsgs] = useState({});
|
||||
|
||||
// Compute a stable key for collapse map (prefer id, else session:index)
|
||||
const collapseKeyFor = (m, i, sessionId) => (m?.id ? m.id : `${sessionId}:${i}`);
|
||||
|
||||
// Initialize/maintain collapsed map whenever messages or the active session change
|
||||
useEffect(() => {
|
||||
if (!activeSessionId) return;
|
||||
|
||||
const msgs =
|
||||
(chatSessions.find(s => s.session_id === activeSessionId)?.messages) || [];
|
||||
|
||||
setCollapsedUserMsgs(prev => {
|
||||
const next = {};
|
||||
msgs.forEach((m, i) => {
|
||||
if (m.role !== 'user') return;
|
||||
const key = collapseKeyFor(m, i, activeSessionId);
|
||||
const lineCount = (m.content || '').split(/\r\n|\r|\n/).length;
|
||||
const needsCollapse = lineCount > 30;
|
||||
// Default collapsed = true when needsCollapse; preserve user toggles
|
||||
next[key] = needsCollapse ? (prev[key] ?? true) : false;
|
||||
});
|
||||
return next;
|
||||
});
|
||||
}, [chatSessions, activeSessionId]);
|
||||
|
||||
// Toggle collapse/expand for a specific message
|
||||
function toggleUserMsgCollapse(key) {
|
||||
setCollapsedUserMsgs(prev => ({ ...prev, [key]: !(prev[key] ?? true) }));
|
||||
}
|
||||
|
||||
const setUserScrolledUp = React.useCallback((sessionId, value) => {
|
||||
setUserScrolledUpState(prev => {
|
||||
const next = { ...prev, [sessionId]: value };
|
||||
@@ -1181,12 +1213,10 @@ export default function App() {
|
||||
<div className="user-message-wrapper">
|
||||
{isEditingThis ? (
|
||||
<div className="msg-content msg-content--user editing">
|
||||
{/* Shadow defines bubble width/height based on current text */}
|
||||
<div className="user-edit-shadow" aria-hidden="true">
|
||||
{editText}
|
||||
</div>
|
||||
|
||||
{/* Overlay textarea fills the bubble exactly */}
|
||||
<TextareaAutosize
|
||||
className="edit-message-input edit-overlay"
|
||||
value={editText}
|
||||
@@ -1201,7 +1231,29 @@ export default function App() {
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="msg-content msg-content--user">{m.content}</div>
|
||||
(() => {
|
||||
const raw = m.content || '';
|
||||
const lines = raw.split(/\r\n|\r|\n/);
|
||||
const needsCollapse = lines.length > 30;
|
||||
const key = collapseKeyFor(m, i, activeSessionId);
|
||||
const isCollapsed = needsCollapse ? (collapsedUserMsgs[key] ?? true) : false;
|
||||
const displayText = isCollapsed ? lines.slice(0, 30).join('\n') + '\n…' : raw;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="msg-content msg-content--user">{displayText}</div>
|
||||
{needsCollapse && (
|
||||
<button
|
||||
className="user-msg-expand"
|
||||
onClick={() => toggleUserMsgCollapse(key)}
|
||||
aria-expanded={isCollapsed ? 'false' : 'true'}
|
||||
>
|
||||
{isCollapsed ? 'Show entire message' : 'Collapse'}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})()
|
||||
)}
|
||||
{!isSending && !isEditingThis && (
|
||||
<div className="message-options-bar user-options">
|
||||
|
||||
@@ -351,15 +351,15 @@ textarea.input {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--accent);
|
||||
color: var(--muted);
|
||||
font-weight: 700; /* bold as requested */
|
||||
cursor: pointer;
|
||||
text-align: left; /* align with text content */
|
||||
align-self: flex-start; /* <-- key line */
|
||||
margin-left: 0; /* ensure no stray left margin */
|
||||
text-align: left; /* you already had this */
|
||||
}
|
||||
|
||||
.msg.user .user-msg-expand:hover {
|
||||
opacity: .9;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.msg.assistant {
|
||||
|
||||
Reference in New Issue
Block a user