|
|
@@ -15,6 +15,7 @@ import Thumbnails from "../common/Thumbnails"
|
|
|
import { vscode } from "../../utils/vscode"
|
|
|
import { WebviewMessage } from "../../../../src/shared/WebviewMessage"
|
|
|
import { Mode } from "../../../../src/core/prompts/types"
|
|
|
+import { CaretIcon } from "../common/CaretIcon"
|
|
|
|
|
|
interface ChatTextAreaProps {
|
|
|
inputValue: string
|
|
|
@@ -50,7 +51,6 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|
|
ref,
|
|
|
) => {
|
|
|
const { filePaths, currentApiConfigName, listApiConfigMeta } = useExtensionState()
|
|
|
- const [isTextAreaFocused, setIsTextAreaFocused] = useState(false)
|
|
|
const [gitCommits, setGitCommits] = useState<any[]>([])
|
|
|
const [showDropdown, setShowDropdown] = useState(false)
|
|
|
|
|
|
@@ -376,7 +376,6 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|
|
if (!isMouseDownOnMenu) {
|
|
|
setShowContextMenu(false)
|
|
|
}
|
|
|
- setIsTextAreaFocused(false)
|
|
|
}, [isMouseDownOnMenu])
|
|
|
|
|
|
const handlePaste = useCallback(
|
|
|
@@ -494,65 +493,97 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|
|
[updateCursorPosition],
|
|
|
)
|
|
|
|
|
|
+ const selectStyle = {
|
|
|
+ fontSize: "11px",
|
|
|
+ cursor: textAreaDisabled ? "not-allowed" : "pointer",
|
|
|
+ backgroundColor: "transparent",
|
|
|
+ border: "none",
|
|
|
+ color: "var(--vscode-foreground)",
|
|
|
+ opacity: textAreaDisabled ? 0.5 : 0.8,
|
|
|
+ outline: "none",
|
|
|
+ paddingLeft: "20px",
|
|
|
+ paddingRight: "6px",
|
|
|
+ WebkitAppearance: "none" as const,
|
|
|
+ MozAppearance: "none" as const,
|
|
|
+ appearance: "none" as const
|
|
|
+ }
|
|
|
+
|
|
|
+ const caretContainerStyle = {
|
|
|
+ position: "absolute" as const,
|
|
|
+ left: 6,
|
|
|
+ top: "50%",
|
|
|
+ transform: "translateY(-45%)",
|
|
|
+ pointerEvents: "none" as const,
|
|
|
+ opacity: textAreaDisabled ? 0.5 : 0.8
|
|
|
+ }
|
|
|
+
|
|
|
return (
|
|
|
- <div style={{
|
|
|
- padding: "10px 15px",
|
|
|
- opacity: textAreaDisabled ? 0.5 : 1,
|
|
|
- position: "relative",
|
|
|
- display: "flex",
|
|
|
- }}
|
|
|
- onDrop={async (e) => {
|
|
|
- e.preventDefault()
|
|
|
- const files = Array.from(e.dataTransfer.files)
|
|
|
- const text = e.dataTransfer.getData("text")
|
|
|
- if (text) {
|
|
|
- const newValue =
|
|
|
- inputValue.slice(0, cursorPosition) + text + inputValue.slice(cursorPosition)
|
|
|
- setInputValue(newValue)
|
|
|
- const newCursorPosition = cursorPosition + text.length
|
|
|
- setCursorPosition(newCursorPosition)
|
|
|
- setIntendedCursorPosition(newCursorPosition)
|
|
|
- return
|
|
|
- }
|
|
|
- const acceptedTypes = ["png", "jpeg", "webp"]
|
|
|
- const imageFiles = files.filter((file) => {
|
|
|
- const [type, subtype] = file.type.split("/")
|
|
|
- return type === "image" && acceptedTypes.includes(subtype)
|
|
|
- })
|
|
|
- if (!shouldDisableImages && imageFiles.length > 0) {
|
|
|
- const imagePromises = imageFiles.map((file) => {
|
|
|
- return new Promise<string | null>((resolve) => {
|
|
|
- const reader = new FileReader()
|
|
|
- reader.onloadend = () => {
|
|
|
- if (reader.error) {
|
|
|
- console.error("Error reading file:", reader.error)
|
|
|
- resolve(null)
|
|
|
- } else {
|
|
|
- const result = reader.result
|
|
|
- resolve(typeof result === "string" ? result : null)
|
|
|
- }
|
|
|
- }
|
|
|
- reader.readAsDataURL(file)
|
|
|
- })
|
|
|
+ <div
|
|
|
+ className="chat-text-area"
|
|
|
+ style={{
|
|
|
+ opacity: textAreaDisabled ? 0.5 : 1,
|
|
|
+ position: "relative",
|
|
|
+ display: "flex",
|
|
|
+ flexDirection: "column",
|
|
|
+ gap: "8px",
|
|
|
+ backgroundColor: "var(--vscode-input-background)",
|
|
|
+ minHeight: "100px",
|
|
|
+ margin: "10px 15px",
|
|
|
+ padding: "8px"
|
|
|
+ }}
|
|
|
+ onDrop={async (e) => {
|
|
|
+ e.preventDefault()
|
|
|
+ const files = Array.from(e.dataTransfer.files)
|
|
|
+ const text = e.dataTransfer.getData("text")
|
|
|
+ if (text) {
|
|
|
+ const newValue =
|
|
|
+ inputValue.slice(0, cursorPosition) + text + inputValue.slice(cursorPosition)
|
|
|
+ setInputValue(newValue)
|
|
|
+ const newCursorPosition = cursorPosition + text.length
|
|
|
+ setCursorPosition(newCursorPosition)
|
|
|
+ setIntendedCursorPosition(newCursorPosition)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const acceptedTypes = ["png", "jpeg", "webp"]
|
|
|
+ const imageFiles = files.filter((file) => {
|
|
|
+ const [type, subtype] = file.type.split("/")
|
|
|
+ return type === "image" && acceptedTypes.includes(subtype)
|
|
|
})
|
|
|
- const imageDataArray = await Promise.all(imagePromises)
|
|
|
- const dataUrls = imageDataArray.filter((dataUrl): dataUrl is string => dataUrl !== null)
|
|
|
- if (dataUrls.length > 0) {
|
|
|
- setSelectedImages((prevImages) => [...prevImages, ...dataUrls].slice(0, MAX_IMAGES_PER_MESSAGE))
|
|
|
- if (typeof vscode !== 'undefined') {
|
|
|
- vscode.postMessage({
|
|
|
- type: 'draggedImages',
|
|
|
- dataUrls: dataUrls
|
|
|
+ if (!shouldDisableImages && imageFiles.length > 0) {
|
|
|
+ const imagePromises = imageFiles.map((file) => {
|
|
|
+ return new Promise<string | null>((resolve) => {
|
|
|
+ const reader = new FileReader()
|
|
|
+ reader.onloadend = () => {
|
|
|
+ if (reader.error) {
|
|
|
+ console.error("Error reading file:", reader.error)
|
|
|
+ resolve(null)
|
|
|
+ } else {
|
|
|
+ const result = reader.result
|
|
|
+ resolve(typeof result === "string" ? result : null)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ reader.readAsDataURL(file)
|
|
|
})
|
|
|
+ })
|
|
|
+ const imageDataArray = await Promise.all(imagePromises)
|
|
|
+ const dataUrls = imageDataArray.filter((dataUrl): dataUrl is string => dataUrl !== null)
|
|
|
+ if (dataUrls.length > 0) {
|
|
|
+ setSelectedImages((prevImages) => [...prevImages, ...dataUrls].slice(0, MAX_IMAGES_PER_MESSAGE))
|
|
|
+ if (typeof vscode !== 'undefined') {
|
|
|
+ vscode.postMessage({
|
|
|
+ type: 'draggedImages',
|
|
|
+ dataUrls: dataUrls
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn("No valid images were processed")
|
|
|
}
|
|
|
- } else {
|
|
|
- console.warn("No valid images were processed")
|
|
|
}
|
|
|
- }
|
|
|
- }}
|
|
|
- onDragOver={(e) => {
|
|
|
- e.preventDefault()
|
|
|
- }}>
|
|
|
+ }}
|
|
|
+ onDragOver={(e) => {
|
|
|
+ e.preventDefault()
|
|
|
+ }}
|
|
|
+ >
|
|
|
{showContextMenu && (
|
|
|
<div ref={contextMenuContainerRef}>
|
|
|
<ContextMenu
|
|
|
@@ -566,101 +597,87 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|
|
/>
|
|
|
</div>
|
|
|
)}
|
|
|
- {!isTextAreaFocused && (
|
|
|
+
|
|
|
+ <div style={{
|
|
|
+ position: "relative",
|
|
|
+ flex: "1 1 auto",
|
|
|
+ display: "flex",
|
|
|
+ flexDirection: "column-reverse",
|
|
|
+ minHeight: 0,
|
|
|
+ overflow: "hidden"
|
|
|
+ }}>
|
|
|
<div
|
|
|
+ ref={highlightLayerRef}
|
|
|
style={{
|
|
|
position: "absolute",
|
|
|
- inset: "10px 15px",
|
|
|
- border: "1px solid var(--vscode-input-border)",
|
|
|
- borderRadius: 2,
|
|
|
+ inset: 0,
|
|
|
pointerEvents: "none",
|
|
|
- zIndex: 5,
|
|
|
+ whiteSpace: "pre-wrap",
|
|
|
+ wordWrap: "break-word",
|
|
|
+ color: "transparent",
|
|
|
+ overflow: "hidden",
|
|
|
+ fontFamily: "var(--vscode-font-family)",
|
|
|
+ fontSize: "var(--vscode-editor-font-size)",
|
|
|
+ lineHeight: "var(--vscode-editor-line-height)",
|
|
|
+ padding: "8px",
|
|
|
+ marginBottom: thumbnailsHeight > 0 ? `${thumbnailsHeight + 16}px` : 0,
|
|
|
+ zIndex: 1
|
|
|
}}
|
|
|
/>
|
|
|
- )}
|
|
|
- <div
|
|
|
- ref={highlightLayerRef}
|
|
|
- style={{
|
|
|
- position: "absolute",
|
|
|
- top: 10,
|
|
|
- left: 15,
|
|
|
- right: 15,
|
|
|
- bottom: 10,
|
|
|
- pointerEvents: "none",
|
|
|
- whiteSpace: "pre-wrap",
|
|
|
- wordWrap: "break-word",
|
|
|
- color: "transparent",
|
|
|
- overflow: "hidden",
|
|
|
- backgroundColor: "var(--vscode-input-background)",
|
|
|
- fontFamily: "var(--vscode-font-family)",
|
|
|
- fontSize: "var(--vscode-editor-font-size)",
|
|
|
- lineHeight: "var(--vscode-editor-line-height)",
|
|
|
- borderRadius: 2,
|
|
|
- borderLeft: 0,
|
|
|
- borderRight: 0,
|
|
|
- borderTop: 0,
|
|
|
- borderColor: "transparent",
|
|
|
- borderBottom: `${thumbnailsHeight + 6}px solid transparent`,
|
|
|
- padding: "9px 9px 25px 9px",
|
|
|
- }}
|
|
|
- />
|
|
|
- <DynamicTextArea
|
|
|
- ref={(el) => {
|
|
|
- if (typeof ref === "function") {
|
|
|
- ref(el)
|
|
|
- } else if (ref) {
|
|
|
- ref.current = el
|
|
|
- }
|
|
|
- textAreaRef.current = el
|
|
|
- }}
|
|
|
- value={inputValue}
|
|
|
- disabled={textAreaDisabled}
|
|
|
- onChange={(e) => {
|
|
|
- handleInputChange(e)
|
|
|
- updateHighlights()
|
|
|
- }}
|
|
|
- onKeyDown={handleKeyDown}
|
|
|
- onKeyUp={handleKeyUp}
|
|
|
- onFocus={() => setIsTextAreaFocused(true)}
|
|
|
- onBlur={handleBlur}
|
|
|
- onPaste={handlePaste}
|
|
|
- onSelect={updateCursorPosition}
|
|
|
- onMouseUp={updateCursorPosition}
|
|
|
- onHeightChange={(height) => {
|
|
|
- if (textAreaBaseHeight === undefined || height < textAreaBaseHeight) {
|
|
|
- setTextAreaBaseHeight(height)
|
|
|
- }
|
|
|
- onHeightChange?.(height)
|
|
|
- }}
|
|
|
- placeholder={placeholderText}
|
|
|
- minRows={2}
|
|
|
- maxRows={20}
|
|
|
- autoFocus={true}
|
|
|
- style={{
|
|
|
- width: "100%",
|
|
|
- boxSizing: "border-box",
|
|
|
- backgroundColor: "transparent",
|
|
|
- color: "var(--vscode-input-foreground)",
|
|
|
- borderRadius: 2,
|
|
|
- fontFamily: "var(--vscode-font-family)",
|
|
|
- fontSize: "var(--vscode-editor-font-size)",
|
|
|
- lineHeight: "var(--vscode-editor-line-height)",
|
|
|
- resize: "none",
|
|
|
- overflowX: "hidden",
|
|
|
- overflowY: "scroll",
|
|
|
- borderLeft: 0,
|
|
|
- borderRight: 0,
|
|
|
- borderTop: 0,
|
|
|
- borderBottom: `${thumbnailsHeight + 6}px solid transparent`,
|
|
|
- borderColor: "transparent",
|
|
|
- padding: "9px 9px 25px 9px",
|
|
|
- marginBottom: "15px",
|
|
|
- cursor: textAreaDisabled ? "not-allowed" : undefined,
|
|
|
- flex: 1,
|
|
|
- zIndex: 1,
|
|
|
- }}
|
|
|
- onScroll={() => updateHighlights()}
|
|
|
- />
|
|
|
+ <DynamicTextArea
|
|
|
+ ref={(el) => {
|
|
|
+ if (typeof ref === "function") {
|
|
|
+ ref(el)
|
|
|
+ } else if (ref) {
|
|
|
+ ref.current = el
|
|
|
+ }
|
|
|
+ textAreaRef.current = el
|
|
|
+ }}
|
|
|
+ value={inputValue}
|
|
|
+ disabled={textAreaDisabled}
|
|
|
+ onChange={(e) => {
|
|
|
+ handleInputChange(e)
|
|
|
+ updateHighlights()
|
|
|
+ }}
|
|
|
+ onKeyDown={handleKeyDown}
|
|
|
+ onKeyUp={handleKeyUp}
|
|
|
+ onBlur={handleBlur}
|
|
|
+ onPaste={handlePaste}
|
|
|
+ onSelect={updateCursorPosition}
|
|
|
+ onMouseUp={updateCursorPosition}
|
|
|
+ onHeightChange={(height) => {
|
|
|
+ if (textAreaBaseHeight === undefined || height < textAreaBaseHeight) {
|
|
|
+ setTextAreaBaseHeight(height)
|
|
|
+ }
|
|
|
+ onHeightChange?.(height)
|
|
|
+ }}
|
|
|
+ placeholder={placeholderText}
|
|
|
+ minRows={4}
|
|
|
+ maxRows={20}
|
|
|
+ autoFocus={true}
|
|
|
+ style={{
|
|
|
+ width: "100%",
|
|
|
+ boxSizing: "border-box",
|
|
|
+ backgroundColor: "transparent",
|
|
|
+ color: "var(--vscode-input-foreground)",
|
|
|
+ borderRadius: 2,
|
|
|
+ fontFamily: "var(--vscode-font-family)",
|
|
|
+ fontSize: "var(--vscode-editor-font-size)",
|
|
|
+ lineHeight: "var(--vscode-editor-line-height)",
|
|
|
+ resize: "none",
|
|
|
+ overflowX: "hidden",
|
|
|
+ overflowY: "auto",
|
|
|
+ border: "none",
|
|
|
+ padding: "8px",
|
|
|
+ marginBottom: thumbnailsHeight > 0 ? `${thumbnailsHeight + 16}px` : 0,
|
|
|
+ cursor: textAreaDisabled ? "not-allowed" : undefined,
|
|
|
+ flex: "0 1 auto",
|
|
|
+ zIndex: 2
|
|
|
+ }}
|
|
|
+ onScroll={() => updateHighlights()}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
{selectedImages.length > 0 && (
|
|
|
<Thumbnails
|
|
|
images={selectedImages}
|
|
|
@@ -668,129 +685,136 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|
|
onHeightChange={handleThumbnailsHeightChange}
|
|
|
style={{
|
|
|
position: "absolute",
|
|
|
- paddingTop: 4,
|
|
|
- bottom: 36,
|
|
|
- left: 22,
|
|
|
- right: 67,
|
|
|
+ bottom: "36px",
|
|
|
+ left: "16px",
|
|
|
zIndex: 2,
|
|
|
+ marginBottom: "8px"
|
|
|
}}
|
|
|
/>
|
|
|
)}
|
|
|
- <div
|
|
|
- style={{
|
|
|
- position: "absolute",
|
|
|
- left: 25,
|
|
|
- bottom: 20,
|
|
|
- zIndex: 3,
|
|
|
+
|
|
|
+ <div style={{
|
|
|
+ display: "flex",
|
|
|
+ justifyContent: "space-between",
|
|
|
+ alignItems: "center",
|
|
|
+ marginTop: "auto",
|
|
|
+ paddingTop: "8px"
|
|
|
+ }}>
|
|
|
+ <div style={{
|
|
|
display: "flex",
|
|
|
- gap: 8,
|
|
|
alignItems: "center"
|
|
|
- }}
|
|
|
- >
|
|
|
- <select
|
|
|
- value={mode}
|
|
|
- disabled={textAreaDisabled}
|
|
|
- onChange={(e) => {
|
|
|
- const newMode = e.target.value as Mode;
|
|
|
- setMode(newMode);
|
|
|
- vscode.postMessage({
|
|
|
- type: "mode",
|
|
|
- text: newMode
|
|
|
- });
|
|
|
- }}
|
|
|
- style={{
|
|
|
- fontSize: "11px",
|
|
|
- cursor: textAreaDisabled ? "not-allowed" : "pointer",
|
|
|
- backgroundColor: "transparent",
|
|
|
- border: "none",
|
|
|
- color: "var(--vscode-input-foreground)",
|
|
|
- opacity: textAreaDisabled ? 0.5 : 0.6,
|
|
|
- outline: "none",
|
|
|
- paddingLeft: 14,
|
|
|
- WebkitAppearance: "none",
|
|
|
- MozAppearance: "none",
|
|
|
- appearance: "none",
|
|
|
- backgroundImage: "url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\")",
|
|
|
- backgroundRepeat: "no-repeat",
|
|
|
- backgroundPosition: "left 0px center",
|
|
|
- backgroundSize: "10px"
|
|
|
- }}>
|
|
|
- <option value="code" style={{
|
|
|
- backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
- color: "var(--vscode-dropdown-foreground)"
|
|
|
- }}>Code</option>
|
|
|
- <option value="architect" style={{
|
|
|
- backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
- color: "var(--vscode-dropdown-foreground)"
|
|
|
- }}>Architect</option>
|
|
|
- <option value="ask" style={{
|
|
|
- backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
- color: "var(--vscode-dropdown-foreground)"
|
|
|
- }}>Ask</option>
|
|
|
- </select>
|
|
|
- <select
|
|
|
- value={currentApiConfigName}
|
|
|
- disabled={textAreaDisabled}
|
|
|
- onChange={(e) => vscode.postMessage({
|
|
|
- type: "loadApiConfiguration",
|
|
|
- text: e.target.value
|
|
|
- })}
|
|
|
- style={{
|
|
|
- fontSize: "11px",
|
|
|
- cursor: textAreaDisabled ? "not-allowed" : "pointer",
|
|
|
- backgroundColor: "transparent",
|
|
|
- border: "none",
|
|
|
- color: "var(--vscode-input-foreground)",
|
|
|
- opacity: textAreaDisabled ? 0.5 : 0.6,
|
|
|
- outline: "none",
|
|
|
- paddingLeft: 14,
|
|
|
- WebkitAppearance: "none",
|
|
|
- MozAppearance: "none",
|
|
|
- appearance: "none",
|
|
|
- backgroundImage: "url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\")",
|
|
|
- backgroundRepeat: "no-repeat",
|
|
|
- backgroundPosition: "left 0px center",
|
|
|
- backgroundSize: "10px"
|
|
|
- }}
|
|
|
- >
|
|
|
- {(listApiConfigMeta || [])?.map((config) => (
|
|
|
- <option
|
|
|
- key={config.name}
|
|
|
- value={config.name}
|
|
|
+ }}>
|
|
|
+ <div style={{ position: "relative", display: "inline-block" }}>
|
|
|
+ <select
|
|
|
+ value={mode}
|
|
|
+ disabled={textAreaDisabled}
|
|
|
+ onChange={(e) => {
|
|
|
+ const newMode = e.target.value as Mode
|
|
|
+ setMode(newMode)
|
|
|
+ vscode.postMessage({
|
|
|
+ type: "mode",
|
|
|
+ text: newMode
|
|
|
+ })
|
|
|
+ }}
|
|
|
style={{
|
|
|
+ ...selectStyle,
|
|
|
+ minWidth: "70px",
|
|
|
+ flex: "0 0 auto"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <option value="code" style={{
|
|
|
backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
color: "var(--vscode-dropdown-foreground)"
|
|
|
+ }}>Code</option>
|
|
|
+ <option value="architect" style={{
|
|
|
+ backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
+ color: "var(--vscode-dropdown-foreground)"
|
|
|
+ }}>Architect</option>
|
|
|
+ <option value="ask" style={{
|
|
|
+ backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
+ color: "var(--vscode-dropdown-foreground)"
|
|
|
+ }}>Ask</option>
|
|
|
+ </select>
|
|
|
+ <div style={caretContainerStyle}>
|
|
|
+ <CaretIcon />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style={{
|
|
|
+ position: "relative",
|
|
|
+ display: "inline-block",
|
|
|
+ flex: "1 1 auto",
|
|
|
+ minWidth: 0,
|
|
|
+ maxWidth: "150px",
|
|
|
+ overflow: "hidden"
|
|
|
+ }}>
|
|
|
+ <select
|
|
|
+ value={currentApiConfigName}
|
|
|
+ disabled={textAreaDisabled}
|
|
|
+ onChange={(e) => vscode.postMessage({
|
|
|
+ type: "loadApiConfiguration",
|
|
|
+ text: e.target.value
|
|
|
+ })}
|
|
|
+ style={{
|
|
|
+ ...selectStyle,
|
|
|
+ width: "100%",
|
|
|
+ textOverflow: "ellipsis"
|
|
|
}}
|
|
|
>
|
|
|
- {config.name}
|
|
|
- </option>
|
|
|
- ))}
|
|
|
- </select>
|
|
|
- </div>
|
|
|
- <div className="button-row" style={{ position: "absolute", right: 16, display: "flex", alignItems: "center", height: 31, bottom: 11, zIndex: 3, padding: "0 8px", justifyContent: "flex-end", backgroundColor: "var(--vscode-input-background)", }}>
|
|
|
- <span style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
|
|
+ {(listApiConfigMeta || [])?.map((config) => (
|
|
|
+ <option
|
|
|
+ key={config.name}
|
|
|
+ value={config.name}
|
|
|
+ style={{
|
|
|
+ backgroundColor: "var(--vscode-dropdown-background)",
|
|
|
+ color: "var(--vscode-dropdown-foreground)"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {config.name}
|
|
|
+ </option>
|
|
|
+ ))}
|
|
|
+ </select>
|
|
|
+ <div style={caretContainerStyle}>
|
|
|
+ <CaretIcon />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style={{
|
|
|
+ display: "flex",
|
|
|
+ alignItems: "center",
|
|
|
+ gap: "12px"
|
|
|
+ }}>
|
|
|
<div style={{ display: "flex", alignItems: "center" }}>
|
|
|
- {isEnhancingPrompt ? (
|
|
|
- <span className="codicon codicon-loading codicon-modifier-spin" style={{
|
|
|
- color: "var(--vscode-input-foreground)",
|
|
|
- opacity: 0.5,
|
|
|
- fontSize: 16.5,
|
|
|
- marginRight: 10
|
|
|
- }}></span>
|
|
|
- ) : (
|
|
|
- <span
|
|
|
- role="button"
|
|
|
- aria-label="enhance prompt"
|
|
|
- data-testid="enhance-prompt-button"
|
|
|
- className={`input-icon-button ${textAreaDisabled ? "disabled" : ""} codicon codicon-sparkle`}
|
|
|
- onClick={() => !textAreaDisabled && handleEnhancePrompt()}
|
|
|
- style={{ fontSize: 16.5 }}
|
|
|
- />
|
|
|
- )}
|
|
|
+ {isEnhancingPrompt ? (
|
|
|
+ <span className="codicon codicon-loading codicon-modifier-spin" style={{
|
|
|
+ color: "var(--vscode-input-foreground)",
|
|
|
+ opacity: 0.5,
|
|
|
+ fontSize: 16.5,
|
|
|
+ marginRight: 10
|
|
|
+ }} />
|
|
|
+ ) : (
|
|
|
+ <span
|
|
|
+ role="button"
|
|
|
+ aria-label="enhance prompt"
|
|
|
+ data-testid="enhance-prompt-button"
|
|
|
+ className={`input-icon-button ${textAreaDisabled ? "disabled" : ""} codicon codicon-sparkle`}
|
|
|
+ onClick={() => !textAreaDisabled && handleEnhancePrompt()}
|
|
|
+ style={{ fontSize: 16.5 }}
|
|
|
+ />
|
|
|
+ )}
|
|
|
</div>
|
|
|
- <span className={`input-icon-button ${shouldDisableImages ? "disabled" : ""} codicon codicon-device-camera`} onClick={() => !shouldDisableImages && onSelectImages()} style={{ fontSize: 16.5 }} />
|
|
|
- <span className={`input-icon-button ${textAreaDisabled ? "disabled" : ""} codicon codicon-send`} onClick={() => !textAreaDisabled && onSend()} style={{ fontSize: 15 }} />
|
|
|
- </span>
|
|
|
+ <span
|
|
|
+ className={`input-icon-button ${shouldDisableImages ? "disabled" : ""} codicon codicon-device-camera`}
|
|
|
+ onClick={() => !shouldDisableImages && onSelectImages()}
|
|
|
+ style={{ fontSize: 16.5 }}
|
|
|
+ />
|
|
|
+ <span
|
|
|
+ className={`input-icon-button ${textAreaDisabled ? "disabled" : ""} codicon codicon-send`}
|
|
|
+ onClick={() => !textAreaDisabled && onSend()}
|
|
|
+ style={{ fontSize: 15 }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
)
|