Make ChatRow layout look good

This commit is contained in:
Saoud Rizwan
2024-07-09 11:39:01 -04:00
parent 661d019bf1
commit 037c6eb226
3 changed files with 102 additions and 74 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState } from "react" import React, { useState } from "react"
import { ClaudeMessage, ClaudeAsk, ClaudeSay } from "@shared/ExtensionMessage" import { ClaudeMessage, ClaudeAsk, ClaudeSay } from "@shared/ExtensionMessage"
import { VSCodeButton, VSCodeProgressRing, VSCodeTag } from "@vscode/webview-ui-toolkit/react" import { VSCodeButton, VSCodeProgressRing, VSCodeBadge } from "@vscode/webview-ui-toolkit/react"
interface ChatRowProps { interface ChatRowProps {
message: ClaudeMessage message: ClaudeMessage
@@ -10,29 +10,71 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
const [isExpanded, setIsExpanded] = useState(false) const [isExpanded, setIsExpanded] = useState(false)
const cost = message.text != null && message.say === "api_req_started" ? JSON.parse(message.text).cost : undefined const cost = message.text != null && message.say === "api_req_started" ? JSON.parse(message.text).cost : undefined
const getIconAndTitle = (type: ClaudeAsk | ClaudeSay | undefined): [JSX.Element | null, string | null] => { const getIconAndTitle = (type: ClaudeAsk | ClaudeSay | undefined): [JSX.Element | null, JSX.Element | null] => {
const normalColor = "var(--vscode-foreground)"
const errorColor = "var(--vscode-errorForeground)"
const successColor = "var(--vscode-testing-iconPassed)"
switch (type) { switch (type) {
case "request_limit_reached": case "request_limit_reached":
return [ return [
<span className="codicon codicon-error" style={{ color: "var(--vscode-errorForeground)" }}></span>, <span
"Max Requests Reached", className="codicon codicon-error"
style={{ color: errorColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: errorColor, fontWeight: "bold" }}>Max Requests Reached</span>,
] ]
case "error": case "error":
return [ return [
<span className="codicon codicon-error" style={{ color: "var(--vscode-errorForeground)" }}></span>, <span
"Error", className="codicon codicon-error"
style={{ color: errorColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: errorColor, fontWeight: "bold" }}>Error</span>,
] ]
case "command": case "command":
return [<span className="codicon codicon-terminal"></span>, "Command"] return [
<span
className="codicon codicon-terminal"
style={{ color: normalColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: normalColor, fontWeight: "bold" }}>Command</span>,
]
case "completion_result": case "completion_result":
return [ return [
<span <span
className="codicon codicon-check" className="codicon codicon-check"
style={{ color: "var(--vscode-testing-iconPassed)" }}></span>, style={{ color: successColor, marginBottom: "-1.5px" }}></span>,
"Task Completed", <span style={{ color: successColor, fontWeight: "bold" }}>Task Completed</span>,
] ]
case "tool": case "tool":
return [<span className="codicon codicon-tools"></span>, "Tool"] return [
<span
className="codicon codicon-tools"
style={{ color: normalColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: normalColor, fontWeight: "bold" }}>Tool</span>,
]
case "api_req_started":
return [
cost ? (
<span
className="codicon codicon-check"
style={{ color: successColor, marginBottom: "-1.5px" }}></span>
) : (
<div
style={{
width: "16px",
height: "16px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}>
<div style={{ transform: "scale(0.55)", transformOrigin: "center" }}>
<VSCodeProgressRing />
</div>
</div>
),
<span style={{ color: normalColor, fontWeight: "bold" }}>
{cost ? "API Request Complete" : "Making API Request..."}
</span>,
]
default: default:
return [null, null] return [null, null]
} }
@@ -44,85 +86,73 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
const headerStyle: React.CSSProperties = { const headerStyle: React.CSSProperties = {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "left",
gap: "10px", gap: "10px",
marginBottom: "10px", marginBottom: "10px",
} }
const contentStyle: React.CSSProperties = { const contentStyle: React.CSSProperties = {
marginLeft: "20px", margin: 0,
} }
switch (message.type) { switch (message.type) {
case "say": case "say":
switch (message.say) { switch (message.say) {
case "task":
return (
<div
style={{
backgroundColor: "var(--vscode-textBlockQuote-background)",
padding: "10px",
borderLeft: "5px solid var(--vscode-textBlockQuote-border)",
}}>
<h3 style={headerStyle}>Task</h3>
<p style={contentStyle}>{message.text}</p>
</div>
)
case "api_req_started": case "api_req_started":
return ( return (
<div> <div style={{ ...headerStyle, marginBottom: 0, justifyContent: "space-between" }}>
<div style={headerStyle}> <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
<span>Made API request...</span> {icon}
{cost ? ( {title}
<span {cost && <VSCodeBadge>${Number(cost).toFixed(4)}</VSCodeBadge>}
className="codicon codicon-check"
style={{ color: "var(--vscode-testing-iconPassed)" }}></span>
) : (
<VSCodeProgressRing />
)}
{cost && <VSCodeTag>{cost}</VSCodeTag>}
<VSCodeButton
appearance="icon"
aria-label="Toggle Details"
onClick={() => setIsExpanded(!isExpanded)}>
<span
className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
</VSCodeButton>
</div> </div>
<VSCodeButton
appearance="icon"
aria-label="Toggle Details"
onClick={() => setIsExpanded(!isExpanded)}>
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
</VSCodeButton>
</div> </div>
) )
case "api_req_finished": case "api_req_finished":
return null // Hide this message type return null // Hide this message type
case "tool": case "tool":
case "error":
case "text": case "text":
case "command_output":
return ( return (
<> <>
{title && ( {title && (
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4>{title}</h4> {title}
</div> </div>
)} )}
<pre style={contentStyle}> <p style={contentStyle}>{message.text}</p>
<code>{message.text}</code> </>
</pre> )
case "error":
return (
<>
{title && (
<div style={headerStyle}>
{icon}
{title}
</div>
)}
<p style={{ ...contentStyle, color: "var(--vscode-errorForeground)" }}>
{message.text}
</p>
</> </>
) )
case "completion_result": case "completion_result":
return ( return (
<div <>
style={{
borderLeft: "5px solid var(--vscode-testing-iconPassed)",
paddingLeft: "10px",
}}>
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4 style={{ color: "var(--vscode-testing-iconPassed)" }}>{title}</h4> {title}
</div> </div>
<p style={contentStyle}>{message.text}</p> <p style={{ ...contentStyle, color: "var(--vscode-testing-iconPassed)" }}>
</div> {message.text}
</p>
</>
) )
default: default:
return ( return (
@@ -130,7 +160,7 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
{title && ( {title && (
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4>{title}</h4> {title}
</div> </div>
)} )}
<p style={contentStyle}>{message.text}</p> <p style={contentStyle}>{message.text}</p>
@@ -144,7 +174,7 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
<> <>
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4>{title}</h4> {title}
</div> </div>
<p style={{ ...contentStyle, color: "var(--vscode-errorForeground)" }}> <p style={{ ...contentStyle, color: "var(--vscode-errorForeground)" }}>
Your task has reached the maximum request limit (maxRequestsPerTask, you can change Your task has reached the maximum request limit (maxRequestsPerTask, you can change
@@ -157,11 +187,11 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
<> <>
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4>{title}</h4> {title}
</div> </div>
<div style={contentStyle}> <div style={contentStyle}>
<p>Claude would like to run this command. Do you allow this?</p> <p>Claude would like to run this command. Do you allow this?</p>
<pre> <pre style={contentStyle}>
<code>{message.text}</code> <code>{message.text}</code>
</pre> </pre>
</div> </div>
@@ -170,16 +200,14 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
case "completion_result": case "completion_result":
if (message.text) { if (message.text) {
return ( return (
<div <div>
style={{
borderLeft: "5px solid var(--vscode-testing-iconPassed)",
paddingLeft: "10px",
}}>
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4 style={{ color: "var(--vscode-testing-iconPassed)" }}>{title}</h4> {title}
</div> </div>
<p style={contentStyle}>{message.text}</p> <p style={{ ...contentStyle, color: "var(--vscode-testing-iconPassed)" }}>
{message.text}
</p>
</div> </div>
) )
} else { } else {
@@ -191,7 +219,7 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
{title && ( {title && (
<div style={headerStyle}> <div style={headerStyle}>
{icon} {icon}
<h4>{title}</h4> {title}
</div> </div>
)} )}
<p style={contentStyle}>{message.text}</p> <p style={contentStyle}>{message.text}</p>
@@ -208,7 +236,7 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
return ( return (
<div <div
style={{ style={{
padding: "10px", padding: "10px 5px 10px 20px",
}}> }}>
{renderContent()} {renderContent()}
{isExpanded && message.say === "api_req_started" && ( {isExpanded && message.say === "api_req_started" && (

View File

@@ -128,7 +128,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
overflow: "hidden", overflow: "hidden",
}}> }}>
<TaskHeader <TaskHeader
taskText="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur." taskText={task?.text || ""}
tokensIn={1000} tokensIn={1000}
tokensOut={1500} tokensOut={1500}
totalCost={0.0025} totalCost={0.0025}
@@ -145,7 +145,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
<div style={{ float: "left", clear: "both" }} ref={messagesEndRef} /> <div style={{ float: "left", clear: "both" }} ref={messagesEndRef} />
</div> </div>
{(primaryButtonText || secondaryButtonText) && ( {(primaryButtonText || secondaryButtonText) && (
<div style={{ display: "flex", padding: "8px 12px 0px 12px" }}> <div style={{ display: "flex", padding: "10px 15px 0px 15px" }}>
{primaryButtonText && ( {primaryButtonText && (
<VSCodeButton <VSCodeButton
appearance="primary" appearance="primary"
@@ -167,7 +167,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
)} )}
</div> </div>
)} )}
<div style={{ padding: "8px 12px" }}> <div style={{ padding: "10px 15px" }}>
<DynamicTextArea <DynamicTextArea
ref={textAreaRef} ref={textAreaRef}
value={inputValue} value={inputValue}
@@ -198,7 +198,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
position: "absolute", position: "absolute",
right: "18px", right: "18px",
height: `${textAreaHeight}px`, height: `${textAreaHeight}px`,
bottom: "10px", bottom: "12px",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
}}> }}>

View File

@@ -15,7 +15,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({ taskText, tokensIn, tokensOut,
return ( return (
<div <div
style={{ style={{
padding: "12px", padding: "15px 15px 10px 15px",
}}> }}>
<div <div
style={{ style={{