diff options
| author | Jay V <[email protected]> | 2025-07-11 14:24:18 -0400 |
|---|---|---|
| committer | Jay V <[email protected]> | 2025-07-11 14:24:20 -0400 |
| commit | 2f1acee5a12b3e60b66cd337690d46f0e36b46be (patch) | |
| tree | 37996106dca0a0b8c46ff30da11a6b9df79f48c4 /packages/web | |
| parent | 9ca54020acc402472cfd76fe5ed65d1564743761 (diff) | |
| download | opencode-2f1acee5a12b3e60b66cd337690d46f0e36b46be.tar.gz opencode-2f1acee5a12b3e60b66cd337690d46f0e36b46be.zip | |
docs: share page add time footer back
Diffstat (limited to 'packages/web')
| -rw-r--r-- | packages/web/src/components/Share.tsx | 1 | ||||
| -rw-r--r-- | packages/web/src/components/share/common.tsx | 17 | ||||
| -rw-r--r-- | packages/web/src/components/share/part.module.css | 6 | ||||
| -rw-r--r-- | packages/web/src/components/share/part.tsx | 190 |
4 files changed, 128 insertions, 86 deletions
diff --git a/packages/web/src/components/Share.tsx b/packages/web/src/components/Share.tsx index 53a249d5b..84e0a1ffb 100644 --- a/packages/web/src/components/Share.tsx +++ b/packages/web/src/components/Share.tsx @@ -364,7 +364,6 @@ export default function Share(props: { <div data-section="part" data-part-type="summary"> <div data-section="decoration"> <span data-status={connectionStatus()[0]}></span> - <div></div> </div> <div data-section="content"> <p data-section="copy">{getStatusText(connectionStatus())}</p> diff --git a/packages/web/src/components/share/common.tsx b/packages/web/src/components/share/common.tsx index 9f5221de9..cab2dbdb0 100644 --- a/packages/web/src/components/share/common.tsx +++ b/packages/web/src/components/share/common.tsx @@ -58,3 +58,20 @@ export function createOverflow() { }, } } + +export function formatDuration(ms: number): string { + const ONE_SECOND = 1000 + const ONE_MINUTE = 60 * ONE_SECOND + + if (ms >= ONE_MINUTE) { + const minutes = Math.floor(ms / ONE_MINUTE) + return minutes === 1 ? `1min` : `${minutes}mins` + } + + if (ms >= ONE_SECOND) { + const seconds = Math.floor(ms / ONE_SECOND) + return `${seconds}s` + } + + return `${ms}ms` +} diff --git a/packages/web/src/components/share/part.module.css b/packages/web/src/components/share/part.module.css index df8102f5d..5ffb83f6b 100644 --- a/packages/web/src/components/share/part.module.css +++ b/packages/web/src/components/share/part.module.css @@ -101,7 +101,12 @@ } [data-component="content"] { + flex: 1 1 auto; min-width: 0; + padding: 0 0 0.375rem; + display: flex; + flex-direction: column; + gap: 1rem; } [data-component="spacer"] { @@ -209,7 +214,6 @@ flex-direction: column; align-items: flex-start; gap: 0.375rem; - padding-bottom: 1rem; &[data-tool="bash"] { max-width: var(--sm-tool-width); diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx index e155332ad..443e4a795 100644 --- a/packages/web/src/components/share/part.tsx +++ b/packages/web/src/components/share/part.tsx @@ -20,6 +20,7 @@ import { IconDocumentMagnifyingGlass, } from "../icons" import { IconMeta, IconOpenAI, IconGemini, IconAnthropic } from "../icons/custom" +import { formatDuration } from "../share/common" import { ContentCode } from "./content-code" import { ContentDiff } from "./content-diff" import { ContentText } from "./content-text" @@ -31,6 +32,8 @@ import type { Diagnostic } from "vscode-languageserver-types" import styles from "./part.module.css" +const MIN_DURATION = 2 + export interface PartProps { index: number message: MessageV2.Info @@ -161,95 +164,104 @@ export function Part(props: PartProps) { {props.part.type === "tool" && props.part.state.status === "error" && ( <div data-component="tool" data-tool="error"> <ContentError>{formatErrorString(props.part.state.error)}</ContentError> + <Spacer /> </div> )} {props.part.type === "tool" && props.part.state.status === "completed" && props.message.role === "assistant" && ( - <div data-component="tool" data-tool={props.part.tool}> - <Switch> - <Match when={props.part.tool === "grep"}> - <GrepTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "glob"}> - <GlobTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "list"}> - <ListTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "read"}> - <ReadTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "write"}> - <WriteTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "edit"}> - <EditTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "bash"}> - <BashTool - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - message={props.message} - /> - </Match> - <Match when={props.part.tool === "todowrite"}> - <TodoWriteTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={props.part.tool === "webfetch"}> - <WebFetchTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - <Match when={true}> - <FallbackTool - message={props.message} - id={props.part.id} - tool={props.part.tool} - state={props.part.state} - /> - </Match> - </Switch> - </div> + <> + <div data-component="tool" data-tool={props.part.tool}> + <Switch> + <Match when={props.part.tool === "grep"}> + <GrepTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "glob"}> + <GlobTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "list"}> + <ListTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "read"}> + <ReadTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "write"}> + <WriteTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "edit"}> + <EditTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "bash"}> + <BashTool + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + message={props.message} + /> + </Match> + <Match when={props.part.tool === "todowrite"}> + <TodoWriteTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={props.part.tool === "webfetch"}> + <WebFetchTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + <Match when={true}> + <FallbackTool + message={props.message} + id={props.part.id} + tool={props.part.tool} + state={props.part.state} + /> + </Match> + </Switch> + </div> + <ToolFooter + time={ + DateTime.fromMillis(props.message.time.completed || 0) + .diff(DateTime.fromMillis(props.message.time.created || 0)) + .toMillis() + } /> + </> )} </div> </div> @@ -623,6 +635,16 @@ 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 /> + ) +} + export function FallbackTool(props: ToolProps) { return ( <> |
