mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Add codicon; add basic chat sidebar with a ResizingTextArea component
This commit is contained in:
@@ -2,83 +2,43 @@ import React from "react"
|
||||
import logo from "./logo.svg"
|
||||
import "./App.css"
|
||||
|
||||
|
||||
import { vscode } from "./utilities/vscode"
|
||||
import {
|
||||
VSCodeBadge,
|
||||
VSCodeButton,
|
||||
VSCodeCheckbox,
|
||||
VSCodeDataGrid,
|
||||
VSCodeDataGridRow,
|
||||
VSCodeDataGridCell,
|
||||
VSCodeTextField,
|
||||
VSCodeDataGridRow,
|
||||
VSCodeDivider,
|
||||
VSCodeDropdown,
|
||||
VSCodeLink,
|
||||
VSCodeOption,
|
||||
VSCodePanels,
|
||||
VSCodePanelTab,
|
||||
VSCodePanelView,
|
||||
VSCodeProgressRing,
|
||||
VSCodeRadio,
|
||||
VSCodeRadioGroup,
|
||||
VSCodeTag,
|
||||
VSCodeTextArea,
|
||||
VSCodeTextField,
|
||||
} from "@vscode/webview-ui-toolkit/react"
|
||||
import ChatSidebar from "./components/ChatSidebar"
|
||||
|
||||
function App() {
|
||||
function handleHowdyClick() {
|
||||
const App: React.FC = () => {
|
||||
const handleHowdyClick = () => {
|
||||
vscode.postMessage({
|
||||
command: "hello",
|
||||
text: "Hey there partner! 🤠",
|
||||
})
|
||||
}
|
||||
|
||||
const rowData = [
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Hello World!</h1>
|
||||
<VSCodeButton onClick={handleHowdyClick}>Howdy!</VSCodeButton>
|
||||
|
||||
<div className="grid gap-3 p-2 place-items-start">
|
||||
<VSCodeDataGrid>
|
||||
<VSCodeDataGridRow row-type="header">
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="1">
|
||||
A Custom Header Title
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="2">
|
||||
Another Custom Title
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="3">
|
||||
Title Is Custom
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="4">
|
||||
Custom Title
|
||||
</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
{rowData.map((row) => (
|
||||
<VSCodeDataGridRow>
|
||||
<VSCodeDataGridCell grid-column="1">{row.cell1}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="2">{row.cell2}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="3">{row.cell3}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="4">{row.cell4}</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
))}
|
||||
</VSCodeDataGrid>
|
||||
|
||||
<span className="flex gap-3">
|
||||
<VSCodeProgressRing />
|
||||
<VSCodeTextField />
|
||||
<VSCodeButton>Add</VSCodeButton>
|
||||
<VSCodeButton appearance="secondary">Remove</VSCodeButton>
|
||||
</span>
|
||||
</div>
|
||||
// REMOVE COLOR
|
||||
<main style={{backgroundColor: '#232526'}}>
|
||||
<ChatSidebar />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
94
webview-ui/src/components/ChatSidebar.tsx
Normal file
94
webview-ui/src/components/ChatSidebar.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React, { useState, useRef, useEffect, useCallback } from "react"
|
||||
import { VSCodeButton, VSCodeTextArea, VSCodeDivider, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { vscode } from "../utilities/vscode"
|
||||
import ResizingTextArea from "./ResizingTextArea"
|
||||
|
||||
interface Message {
|
||||
id: number
|
||||
text: string
|
||||
sender: "user" | "assistant"
|
||||
}
|
||||
|
||||
const ChatSidebar = () => {
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
const [inputValue, setInputValue] = useState("")
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
|
||||
useEffect(scrollToBottom, [messages])
|
||||
|
||||
const handleSendMessage = () => {
|
||||
if (inputValue.trim()) {
|
||||
const newMessage: Message = {
|
||||
id: Date.now(),
|
||||
text: inputValue.trim(),
|
||||
sender: "user",
|
||||
}
|
||||
setMessages([...messages, newMessage])
|
||||
setInputValue("")
|
||||
// if (textAreaRef.current) {
|
||||
// textAreaRef.current.style.height = "auto"
|
||||
// }
|
||||
|
||||
// Here you would typically send the message to your extension's backend
|
||||
vscode.postMessage({
|
||||
command: "sendMessage",
|
||||
text: newMessage.text,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="chat-sidebar" style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
|
||||
<div className="message-list" style={{ flexGrow: 1, overflowY: "auto", padding: "10px" }}>
|
||||
{messages.map((message) => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`message ${message.sender}`}
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
padding: "8px",
|
||||
borderRadius: "4px",
|
||||
backgroundColor:
|
||||
message.sender === "user"
|
||||
? "var(--vscode-editor-background)"
|
||||
: "var(--vscode-sideBar-background)",
|
||||
}}>
|
||||
{message.text}
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
<VSCodeDivider />
|
||||
<div className="input-area" style={{ padding: 20 }}>
|
||||
<ResizingTextArea
|
||||
value={inputValue}
|
||||
onChange={setInputValue}
|
||||
placeholder="Type a message..."
|
||||
style={{ marginBottom: "10px", width: "100%" }}
|
||||
/>
|
||||
<VSCodeButton onClick={handleSendMessage}>Send</VSCodeButton>
|
||||
<VSCodeTextField>
|
||||
<section slot="end" style={{ display: "flex", alignItems: "center" }}>
|
||||
<VSCodeButton appearance="icon" aria-label="Match Case">
|
||||
<span className="codicon codicon-case-sensitive"></span>
|
||||
</VSCodeButton>
|
||||
<VSCodeButton appearance="icon" aria-label="Match Whole Word">
|
||||
<span className="codicon codicon-whole-word"></span>
|
||||
</VSCodeButton>
|
||||
<VSCodeButton appearance="icon" aria-label="Use Regular Expression">
|
||||
<span className="codicon codicon-regex"></span>
|
||||
</VSCodeButton>
|
||||
</section>
|
||||
</VSCodeTextField>
|
||||
<span slot="end" className="codicon codicon-chevron-right"></span>
|
||||
<VSCodeButton onClick={handleSendMessage}>Send</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChatSidebar
|
||||
132
webview-ui/src/components/Demo.tsx
Normal file
132
webview-ui/src/components/Demo.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
import { vscode } from "../utilities/vscode"
|
||||
import {
|
||||
VSCodeBadge,
|
||||
VSCodeButton,
|
||||
VSCodeCheckbox,
|
||||
VSCodeDataGrid,
|
||||
VSCodeDataGridCell,
|
||||
VSCodeDataGridRow,
|
||||
VSCodeDivider,
|
||||
VSCodeDropdown,
|
||||
VSCodeLink,
|
||||
VSCodeOption,
|
||||
VSCodePanels,
|
||||
VSCodePanelTab,
|
||||
VSCodePanelView,
|
||||
VSCodeProgressRing,
|
||||
VSCodeRadio,
|
||||
VSCodeRadioGroup,
|
||||
VSCodeTag,
|
||||
VSCodeTextArea,
|
||||
VSCodeTextField,
|
||||
} from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
function Demo() {
|
||||
function handleHowdyClick() {
|
||||
vscode.postMessage({
|
||||
command: "hello",
|
||||
text: "Hey there partner! 🤠",
|
||||
})
|
||||
}
|
||||
|
||||
const rowData = [
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
{
|
||||
cell1: "Cell Data",
|
||||
cell2: "Cell Data",
|
||||
cell3: "Cell Data",
|
||||
cell4: "Cell Data",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Hello World!</h1>
|
||||
<VSCodeButton onClick={handleHowdyClick}>Howdy!</VSCodeButton>
|
||||
|
||||
<div className="grid gap-3 p-2 place-items-start">
|
||||
<VSCodeDataGrid>
|
||||
<VSCodeDataGridRow row-type="header">
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="1">
|
||||
A Custom Header Title
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="2">
|
||||
Another Custom Title
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="3">
|
||||
Title Is Custom
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell cell-type="columnheader" grid-column="4">
|
||||
Custom Title
|
||||
</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
{rowData.map((row, index) => (
|
||||
<VSCodeDataGridRow key={index}>
|
||||
<VSCodeDataGridCell grid-column="1">{row.cell1}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="2">{row.cell2}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="3">{row.cell3}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="4">{row.cell4}</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
))}
|
||||
</VSCodeDataGrid>
|
||||
|
||||
<VSCodeTextField>
|
||||
<section slot="end" style={{ display: "flex", alignItems: "center" }}>
|
||||
<VSCodeButton appearance="icon" aria-label="Match Case">
|
||||
<span className="codicon codicon-case-sensitive"></span>
|
||||
</VSCodeButton>
|
||||
<VSCodeButton appearance="icon" aria-label="Match Whole Word">
|
||||
<span className="codicon codicon-whole-word"></span>
|
||||
</VSCodeButton>
|
||||
<VSCodeButton appearance="icon" aria-label="Use Regular Expression">
|
||||
<span className="codicon codicon-regex"></span>
|
||||
</VSCodeButton>
|
||||
</section>
|
||||
</VSCodeTextField>
|
||||
<span slot="end" className="codicon codicon-chevron-right"></span>
|
||||
|
||||
<span className="flex gap-3">
|
||||
<VSCodeProgressRing />
|
||||
<VSCodeTextField />
|
||||
<VSCodeButton>Add</VSCodeButton>
|
||||
<VSCodeButton appearance="secondary">Remove</VSCodeButton>
|
||||
</span>
|
||||
|
||||
<VSCodeBadge>Badge</VSCodeBadge>
|
||||
<VSCodeCheckbox>Checkbox</VSCodeCheckbox>
|
||||
<VSCodeDivider />
|
||||
<VSCodeDropdown>
|
||||
<VSCodeOption>Option 1</VSCodeOption>
|
||||
<VSCodeOption>Option 2</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
<VSCodeLink href="#">Link</VSCodeLink>
|
||||
<VSCodePanels>
|
||||
<VSCodePanelTab id="tab-1">Tab 1</VSCodePanelTab>
|
||||
<VSCodePanelTab id="tab-2">Tab 2</VSCodePanelTab>
|
||||
<VSCodePanelView id="view-1">Panel View 1</VSCodePanelView>
|
||||
<VSCodePanelView id="view-2">Panel View 2</VSCodePanelView>
|
||||
</VSCodePanels>
|
||||
<VSCodeRadioGroup>
|
||||
<VSCodeRadio>Radio 1</VSCodeRadio>
|
||||
<VSCodeRadio>Radio 2</VSCodeRadio>
|
||||
</VSCodeRadioGroup>
|
||||
<VSCodeTag>Tag</VSCodeTag>
|
||||
<VSCodeTextArea placeholder="Text Area" />
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
export default Demo
|
||||
46
webview-ui/src/components/ResizingTextArea.tsx
Normal file
46
webview-ui/src/components/ResizingTextArea.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React, { TextareaHTMLAttributes, CSSProperties, useRef, useEffect } from "react"
|
||||
|
||||
interface ResizingTextAreaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
|
||||
const ResizingTextArea= ({ style, value, onChange, ...props }: ResizingTextAreaProps) => {
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
const textareaStyle: CSSProperties = {
|
||||
width: "100%",
|
||||
minHeight: "60px",
|
||||
backgroundColor: "var(--vscode-input-background, #3c3c3c)",
|
||||
color: "var(--vscode-input-foreground, #cccccc)",
|
||||
border: "1px solid var(--vscode-input-border, #3c3c3c)",
|
||||
borderRadius: "2px",
|
||||
padding: "4px 8px",
|
||||
outline: "none",
|
||||
fontFamily: "var(--vscode-editor-font-family)",
|
||||
fontSize: "var(--vscode-editor-font-size, 13px)",
|
||||
lineHeight: "var(--vscode-editor-line-height, 1.5)",
|
||||
resize: "none",
|
||||
overflow: "hidden",
|
||||
...style,
|
||||
}
|
||||
|
||||
const adjustTextAreaHeight = () => {
|
||||
if (textAreaRef.current) {
|
||||
textAreaRef.current.style.height = "auto"
|
||||
textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`
|
||||
}
|
||||
}
|
||||
|
||||
const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
onChange(event.target.value)
|
||||
adjustTextAreaHeight()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustTextAreaHeight()
|
||||
}, [value])
|
||||
|
||||
return <textarea ref={textAreaRef} style={textareaStyle} value={value} onChange={handleInputChange} {...props} />
|
||||
}
|
||||
|
||||
export default ResizingTextArea
|
||||
@@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client"
|
||||
import "./index.css"
|
||||
import App from "./App"
|
||||
import reportWebVitals from "./reportWebVitals"
|
||||
import "../../node_modules/@vscode/codicons/dist/codicon.css"
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
||||
root.render(
|
||||
|
||||
Reference in New Issue
Block a user