mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Add codicon; add basic chat sidebar with a ResizingTextArea component
This commit is contained in:
35
README.md
35
README.md
@@ -1,3 +1,38 @@
|
||||
|
||||
# Icon library
|
||||
This repo uses https://github.com/microsoft/vscode-codicons
|
||||
https://microsoft.github.io/vscode-codicons/dist/codicon.html
|
||||
|
||||
|
||||
# Styling VSCode Webview UI Toolkit Components
|
||||
|
||||
## Understanding Styling Constraints
|
||||
|
||||
When working with the VSCode Webview UI Toolkit, it's important to understand the styling constraints imposed by the underlying architecture. The toolkit uses Microsoft's FAST framework, which utilizes Shadow DOM for component encapsulation. This approach ensures consistency with VSCode's design language but introduces some limitations in custom styling.
|
||||
|
||||
### Key Points:
|
||||
|
||||
- **Shadow DOM Encapsulation**: The toolkit components use Shadow DOM, which encapsulates the internal structure of components. This means that traditional CSS selectors cannot directly target elements within the component.
|
||||
|
||||
- **Wrapper vs. Shadow Element**: When you apply styles to a toolkit component, you're typically styling the wrapper element, not the shadow element inside. This can lead to unexpected results if you're trying to modify the internal appearance of a component.
|
||||
|
||||
- **Use Props for Behavior Modification**: Instead of relying on custom styles, you should primarily use the props provided by the toolkit components to modify their behavior and appearance. This ensures consistency with VSCode's design language and prevents potential conflicts.
|
||||
|
||||
- **Limited Direct Styling**: While it's possible to style some internal elements using the `::part()` pseudo-element selector, this approach is not officially supported or documented by the toolkit. Using it may lead to inconsistencies with VSCode's native UI.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Stick to Provided Props**: Whenever possible, use the props and attributes provided by the toolkit components to customize their appearance and behavior.
|
||||
|
||||
2. **Avoid Custom Styles**: Refrain from applying custom styles that significantly alter the appearance of toolkit components. This helps maintain consistency with VSCode's native UI.
|
||||
|
||||
3. **Use Wrapper Styles Carefully**: If you need to apply styles, focus on the wrapper element (e.g., positioning, margins) rather than trying to modify the internal shadow elements.
|
||||
|
||||
### Sources
|
||||
- https://github.com/microsoft/vscode-webview-ui-toolkit/issues/376#issuecomment-1191881962
|
||||
- https://github.com/microsoft/vscode-webview-ui-toolkit/issues/550#issuecomment-2148407785
|
||||
|
||||
|
||||
# claude-dev README
|
||||
|
||||
This is the README for your extension "claude-dev". After writing up a brief description, we recommend including the following sections.
|
||||
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -7,6 +7,9 @@
|
||||
"": {
|
||||
"name": "claude-dev",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@vscode/codicons": "^0.0.36"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^10.0.7",
|
||||
"@types/node": "20.x",
|
||||
@@ -933,6 +936,12 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@vscode/codicons": {
|
||||
"version": "0.0.36",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.36.tgz",
|
||||
"integrity": "sha512-wsNOvNMMJ2BY8rC2N2MNBG7yOowV3ov8KlvUE/AiVUlHKTfWsw3OgAOQduX7h0Un6GssKD3aoTVH+TF3DSQwKQ==",
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/@vscode/test-cli": {
|
||||
"version": "0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.9.tgz",
|
||||
|
||||
@@ -77,5 +77,8 @@
|
||||
"eslint": "^8.57.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vscode/codicons": "^0.0.36"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,12 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
|
||||
// The JS file from the React build output
|
||||
const scriptUri = getUri(webview, this._extensionUri, ["webview-ui", "build", "static", "js", "main.js"])
|
||||
|
||||
// The codicon font from the React build output
|
||||
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-codicons-sample/src/extension.ts
|
||||
// we installed this package in the extension so that we can access it how its intended from the extension (the font file is likely bundled in vscode), and we just import the css fileinto our react app we don't have access to it
|
||||
// don't forget to add font-src ${webview.cspSource};
|
||||
const codiconsUri = getUri(webview, this._extensionUri, ["node_modules", "@vscode", "codicons", "dist", "codicon.css"])
|
||||
|
||||
// const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.js"))
|
||||
|
||||
// const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "reset.css"))
|
||||
@@ -84,8 +90,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${webview.cspSource}; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
|
||||
<link rel="stylesheet" type="text/css" href="${stylesUri}">
|
||||
<link href="${codiconsUri}" rel="stylesheet" />
|
||||
<title>Claude Dev</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -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