summaryrefslogtreecommitdiffhomepage
path: root/packages/web/src/components/share
diff options
context:
space:
mode:
authorJay V <[email protected]>2025-07-15 17:12:09 -0400
committerJay V <[email protected]>2025-07-15 17:47:22 -0400
commit749e7838a444d6f2f846bd7e6e008edae25b0c69 (patch)
tree2600d24c2bf539893da6d9977e44293e835d9294 /packages/web/src/components/share
parent73b46c2bf9090094a5e31db62ef16fe1b08bb01e (diff)
downloadopencode-749e7838a444d6f2f846bd7e6e008edae25b0c69.tar.gz
opencode-749e7838a444d6f2f846bd7e6e008edae25b0c69.zip
docs: share page task tool
Diffstat (limited to 'packages/web/src/components/share')
-rw-r--r--packages/web/src/components/share/content-markdown.module.css16
-rw-r--r--packages/web/src/components/share/content-markdown.tsx10
-rw-r--r--packages/web/src/components/share/part.module.css28
-rw-r--r--packages/web/src/components/share/part.tsx60
4 files changed, 76 insertions, 38 deletions
diff --git a/packages/web/src/components/share/content-markdown.module.css b/packages/web/src/components/share/content-markdown.module.css
index 0e6b83620..3e38ddf02 100644
--- a/packages/web/src/components/share/content-markdown.module.css
+++ b/packages/web/src/components/share/content-markdown.module.css
@@ -1,21 +1,13 @@
.root {
- border: 1px solid var(--sl-color-blue-high);
- padding: 0.5rem calc(0.5rem + 3px);
- border-radius: 0.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 1rem;
- align-self: flex-start;
-
- &[data-highlight="true"] {
- background-color: var(--sl-color-blue-low);
- }
[data-slot="expand-button"] {
flex: 0 0 auto;
padding: 2px 0;
- font-size: 0.75rem;
+ font-size: 0.857em;
}
[data-slot="markdown"] {
@@ -29,7 +21,7 @@
display: block;
}
- font-size: 0.875rem;
+ font-size: 1em;
line-height: 1.5;
p,
@@ -61,7 +53,7 @@
h4,
h5,
h6 {
- font-size: 0.875rem;
+ font-size: 1em;
font-weight: 600;
margin-bottom: 0.5rem;
}
@@ -75,7 +67,7 @@
background-color: var(--sl-color-bg-surface) !important;
padding: 0.5rem 0.75rem;
line-height: 1.6;
- font-size: 0.75rem;
+ font-size: 0.857em;
white-space: pre-wrap;
word-break: break-word;
diff --git a/packages/web/src/components/share/content-markdown.tsx b/packages/web/src/components/share/content-markdown.tsx
index f79271296..a083872e7 100644
--- a/packages/web/src/components/share/content-markdown.tsx
+++ b/packages/web/src/components/share/content-markdown.tsx
@@ -1,10 +1,10 @@
-import style from "./content-markdown.module.css"
-import { createResource, createSignal } from "solid-js"
-import { createOverflow } from "./common"
-import { transformerNotationDiff } from "@shikijs/transformers"
import { marked } from "marked"
-import markedShiki from "marked-shiki"
import { codeToHtml } from "shiki"
+import markedShiki from "marked-shiki"
+import { createOverflow } from "./common"
+import { createResource, createSignal } from "solid-js"
+import { transformerNotationDiff } from "@shikijs/transformers"
+import style from "./content-markdown.module.css"
const markedWithShiki = marked.use(
markedShiki({
diff --git a/packages/web/src/components/share/part.module.css b/packages/web/src/components/share/part.module.css
index 5ffb83f6b..17018fa02 100644
--- a/packages/web/src/components/share/part.module.css
+++ b/packages/web/src/components/share/part.module.css
@@ -103,7 +103,7 @@
[data-component="content"] {
flex: 1 1 auto;
min-width: 0;
- padding: 0 0 0.375rem;
+ padding: 0 0 1rem;
display: flex;
flex-direction: column;
gap: 1rem;
@@ -135,6 +135,14 @@
gap: 1rem;
flex-grow: 1;
max-width: var(--md-tool-width);
+
+ & > [data-component="assistant-text-markdown"] {
+ align-self: flex-start;
+ font-size: 0.875rem;
+ border: 1px solid var(--sl-color-blue-high);
+ padding: 0.5rem calc(0.5rem + 3px);
+ border-radius: 0.25rem;
+ }
}
[data-component="step-start"] {
@@ -239,6 +247,24 @@
max-width: var(--lg-tool-width);
}
}
+ &[data-tool="task"] {
+ [data-component="tool-input"] {
+ font-size: 0.75rem;
+ line-height: 1.5;
+ max-width: var(--sm-tool-width);
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ }
+ [data-component="tool-output"] {
+ max-width: var(--sm-tool-width);
+ font-size: 0.75rem;
+ border: 1px solid var(--sl-color-divider);
+ padding: 0.5rem calc(0.5rem + 3px);
+ border-radius: 0.25rem;
+ }
+ }
}
[data-component="tool-title"] {
diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx
index fcfa8bec4..4a9320e6d 100644
--- a/packages/web/src/components/share/part.tsx
+++ b/packages/web/src/components/share/part.tsx
@@ -19,25 +19,25 @@ import {
IconMagnifyingGlass,
IconDocumentMagnifyingGlass,
} from "../icons"
-import { IconMeta, IconOpenAI, IconGemini, IconAnthropic } from "../icons/custom"
-import { formatDuration } from "../share/common"
+import { IconMeta, IconRobot, IconOpenAI, IconGemini, IconAnthropic } from "../icons/custom"
import { ContentCode } from "./content-code"
import { ContentDiff } from "./content-diff"
import { ContentText } from "./content-text"
+import { ContentBash } from "./content-bash"
import { ContentError } from "./content-error"
+import { formatDuration } from "../share/common"
import { ContentMarkdown } from "./content-markdown"
-import { ContentBash } from "./content-bash"
import type { MessageV2 } from "opencode/session/message-v2"
import type { Diagnostic } from "vscode-languageserver-types"
import styles from "./part.module.css"
-const MIN_DURATION = 2
+const MIN_DURATION = 2000
export interface PartProps {
index: number
message: MessageV2.Info
- part: MessageV2.AssistantPart | MessageV2.UserPart
+ part: MessageV2.Part
last: boolean
}
@@ -114,7 +114,7 @@ export function Part(props: PartProps) {
<IconGlobeAlt width={18} height={18} />
</Match>
<Match when={props.part.type === "tool" && props.part.tool === "task"}>
- <IconRectangleStack width={18} height={18} />
+ <IconRobot width={18} height={18} />
</Match>
<Match when={true}>
<IconSparkles width={18} height={18} />
@@ -131,12 +131,13 @@ export function Part(props: PartProps) {
{props.message.role === "user" && props.part.type === "text" && (
<div data-component="user-text">
<ContentText text={props.part.text} expand={props.last} />
- <Spacer />
</div>
)}
{props.message.role === "assistant" && props.part.type === "text" && (
<div data-component="assistant-text">
- <ContentMarkdown expand={props.last} text={props.part.text} />
+ <div data-component="assistant-text-markdown">
+ <ContentMarkdown expand={props.last} text={props.part.text} />
+ </div>
{props.last && props.message.role === "assistant" && props.message.time.completed && (
<Footer
title={DateTime.fromMillis(props.message.time.completed).toLocaleString(
@@ -146,7 +147,6 @@ export function Part(props: PartProps) {
{DateTime.fromMillis(props.message.time.completed).toLocaleString(DateTime.DATETIME_MED)}
</Footer>
)}
- <Spacer />
</div>
)}
{props.message.role === "user" && props.part.type === "file" && (
@@ -245,6 +245,14 @@ export function Part(props: PartProps) {
state={props.part.state}
/>
</Match>
+ <Match when={props.part.tool === "task"}>
+ <TaskTool
+ id={props.part.id}
+ tool={props.part.tool}
+ message={props.message}
+ state={props.part.state}
+ />
+ </Match>
<Match when={true}>
<FallbackTool
message={props.message}
@@ -256,11 +264,10 @@ export function Part(props: PartProps) {
</Switch>
</div>
<ToolFooter
- time={
- DateTime.fromMillis(props.part.state.time.start)
- .diff(DateTime.fromMillis(props.part.state.time.end))
- .toMillis()
- } />
+ time={DateTime.fromMillis(props.part.state.time.end)
+ .diff(DateTime.fromMillis(props.part.state.time.start))
+ .toMillis()}
+ />
</>
)}
</div>
@@ -636,12 +643,25 @@ function Footer(props: ParentProps<{ title: string }>) {
}
function ToolFooter(props: { time: number }) {
- return props.time > MIN_DURATION ? (
- <Footer title={`${props.time}ms`}>
- {formatDuration(props.time)}
- </Footer>
- ) : (
- <Spacer />
+ return props.time > MIN_DURATION && <Footer title={`${props.time}ms`}>{formatDuration(props.time)}</Footer>
+}
+
+function TaskTool(props: ToolProps) {
+ return (
+ <>
+ <div data-component="tool-title">
+ <span data-slot="name">Task</span>
+ <span data-slot="target">{props.state.input.description}</span>
+ </div>
+ <div data-component="tool-input">
+ &ldquo;{props.state.input.prompt}&rdquo;
+ </div>
+ <ResultsButton showCopy="Show output" hideCopy="Hide output">
+ <div data-component="tool-output">
+ <ContentMarkdown expand text={props.state.output} />
+ </div>
+ </ResultsButton>
+ </>
)
}