Просмотр исходного кода

docs: share page add time footer back

Jay V 7 месяцев назад
Родитель
Сommit
2f1acee5a1

+ 0 - 1
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>

+ 17 - 0
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`
+}

+ 5 - 1
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);

+ 106 - 84
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 (
     <>