read tool share page

This commit is contained in:
Jay V
2025-06-04 18:39:03 -04:00
parent f76cdfff9b
commit a74f27e59a
2 changed files with 200 additions and 3 deletions

View File

@@ -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={

View File

@@ -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] {