diff options
| author | Jay V <[email protected]> | 2025-06-04 18:39:03 -0400 |
|---|---|---|
| committer | Jay V <[email protected]> | 2025-06-04 18:39:06 -0400 |
| commit | a74f27e59a5fcb20ecdf4add6b981b33ac9735cc (patch) | |
| tree | 90c44cb9974272f7d5c6241e782b754d7f55d5c4 /packages | |
| parent | f76cdfff9b28b7632bcbcf2a58172ce2f5e6cec0 (diff) | |
| download | opencode-a74f27e59a5fcb20ecdf4add6b981b33ac9735cc.tar.gz opencode-a74f27e59a5fcb20ecdf4add6b981b33ac9735cc.zip | |
read tool share page
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/web/src/components/Share.tsx | 169 | ||||
| -rw-r--r-- | packages/web/src/components/share.module.css | 34 |
2 files changed, 200 insertions, 3 deletions
diff --git a/packages/web/src/components/Share.tsx b/packages/web/src/components/Share.tsx index d1874afb6..15bc7fdc2 100644 --- a/packages/web/src/components/Share.tsx +++ b/packages/web/src/components/Share.tsx @@ -21,7 +21,9 @@ import { IconCommandLine, IconChevronRight, IconPencilSquare, + IconRectangleStack, IconWrenchScrewdriver, + IconDocumentArrowDown, } from "./icons" import DiffView from "./DiffView" import CodeBlock from "./CodeBlock" @@ -158,10 +160,12 @@ function ProviderIcon(props: { provider: string; size?: number }) { } interface ResultsButtonProps extends JSX.HTMLAttributes<HTMLButtonElement> { + showCopy?: string + hideCopy?: string results: boolean } function ResultsButton(props: ResultsButtonProps) { - const [local, rest] = splitProps(props, ["results"]) + const [local, rest] = splitProps(props, ["results", "showCopy", "hideCopy"]) return ( <button type="button" @@ -169,7 +173,11 @@ function ResultsButton(props: ResultsButtonProps) { data-element-button-more {...rest} > - <span>{local.results ? "Hide results" : "Show results"}</span> + <span> + {local.results + ? local.hideCopy || "Hide results" + : local.showCopy || "Show results"} + </span> <span data-button-icon> <Show when={local.results} @@ -726,6 +734,163 @@ export default function Share(props: { api: string }) { </div> )} </Match> + {/* LS tool */} + <Match + when={ + msg.role === "assistant" && + part.type === "tool-invocation" && + part.toolInvocation.toolName === "opencode_list" && + part + } + > + {(part) => { + const metadata = createMemo(() => + msg.metadata?.tool[part().toolInvocation.toolCallId] + ) + const args = part().toolInvocation.args + const path = args.path + + const duration = createMemo(() => + DateTime.fromMillis(metadata()?.time.end || 0).diff( + DateTime.fromMillis(metadata()?.time.start || 0), + ).toMillis(), + ) + + return ( + <div data-section="part" data-part-type="tool-list"> + <div data-section="decoration"> + <div title="List files"> + <IconRectangleStack width={18} height={18} /> + </div> + <div></div> + </div> + <div data-section="content"> + <div data-part-tool-body> + <span data-part-title data-size="md"> + <span data-element-label>LS</span> + <b>{path}</b> + </span> + <Switch> + <Match + when={ + part().toolInvocation.state === + "result" && + part().toolInvocation.result + } + > + <div data-part-tool-result> + <ResultsButton + results={results()} + onClick={() => showResults((e) => !e)} + /> + <Show when={results()}> + <TextPart + expand + data-size="sm" + data-color="dimmed" + text={part().toolInvocation.result} + /> + </Show> + </div> + </Match> + </Switch> + </div> + <ToolFooter time={duration()} /> + </div> + </div> + ) + }} + </Match> + {/* Read tool */} + <Match + when={ + msg.role === "assistant" && + part.type === "tool-invocation" && + part.toolInvocation.toolName === "opencode_read" && + part + } + > + {(part) => { + const metadata = createMemo(() => msg.metadata?.tool[part().toolInvocation.toolCallId]) + const args = part().toolInvocation.args + const filePath = args.filePath + const hasError = metadata()?.error + const preview = metadata()?.preview + const result = part().toolInvocation.state === "result" && part().toolInvocation.result + + const duration = createMemo(() => + DateTime.fromMillis(metadata()?.time.end || 0).diff( + DateTime.fromMillis(metadata()?.time.start || 0), + ).toMillis(), + ) + + return ( + <div data-section="part" data-part-type="tool-read"> + <div data-section="decoration"> + <div title="Read file"> + <IconDocumentArrowDown width={18} height={18} /> + </div> + <div></div> + </div> + <div data-section="content"> + <div data-part-tool-body> + <span data-part-title data-size="md"> + <span data-element-label>Read</span> + <b>{filePath}</b> + </span> + <Switch> + <Match when={hasError}> + <div data-part-tool-result> + <TextPart + expand + text={result} + data-size="sm" + data-color="dimmed" + /> + </div> + </Match> + <Match when={preview}> + <div data-part-tool-result> + <ResultsButton + showCopy="Show preview" + hideCopy="Hide preview" + results={results()} + onClick={() => showResults((e) => !e)} + /> + <Show when={results()}> + <div data-part-tool-code> + <CodeBlock + lang={getFileType(filePath)} + code={preview} + /> + </div> + </Show> + </div> + </Match> + <Match when={result}> + <div data-part-tool-result> + <ResultsButton + results={results()} + onClick={() => showResults((e) => !e)} + /> + <Show when={results()}> + <TextPart + expand + text={result} + data-size="sm" + data-color="dimmed" + /> + </Show> + </div> + </Match> + </Switch> + </div> + <ToolFooter time={duration()} /> + </div> + </div> + ) + }} + </Match> {/* Edit tool */} <Match when={ diff --git a/packages/web/src/components/share.module.css b/packages/web/src/components/share.module.css index f29343ed5..bedc1a3eb 100644 --- a/packages/web/src/components/share.module.css +++ b/packages/web/src/components/share.module.css @@ -314,8 +314,40 @@ } } + [data-part-type="tool-list"], + [data-part-type="tool-read"] { + & > [data-section="content"] > [data-part-tool-body] { + gap: 0.5rem; + } + [data-part-title] { + display: flex; + align-items: flex-start; + gap: 0.5rem; + + b { + color: var(--sl-color-text); + word-break: break-all; + } + } + } + + [data-part-type="tool-read"] { + [data-part-tool-result] { + [data-part-tool-code] { + border: 1px solid var(--sl-color-divider); + border-radius: 0.25rem; + padding: 0.5rem calc(0.5rem + 3px); + + pre { + line-height: 1.6; + font-size: 0.75rem; + } + } + } + } + [data-part-type="tool-edit"] { - [data-part-tool-body] { + & > [data-section="content"] > [data-part-tool-body] { gap: 0.5rem; } [data-part-title] { |
