diff options
| author | Jay V <[email protected]> | 2025-05-27 20:38:23 -0400 |
|---|---|---|
| committer | Jay V <[email protected]> | 2025-05-27 20:38:29 -0400 |
| commit | 37082b217653b33da1ff5318293ceec28a253f9b (patch) | |
| tree | c762d61812918f2c56e970e32c066b13a44d5732 /app/packages/web/src/components/Share.tsx | |
| parent | b9f009c529e7d70484ba2674547f050c55862ca4 (diff) | |
| download | opencode-37082b217653b33da1ff5318293ceec28a253f9b.tar.gz opencode-37082b217653b33da1ff5318293ceec28a253f9b.zip | |
styling share
Diffstat (limited to 'app/packages/web/src/components/Share.tsx')
| -rw-r--r-- | app/packages/web/src/components/Share.tsx | 125 |
1 files changed, 108 insertions, 17 deletions
diff --git a/app/packages/web/src/components/Share.tsx b/app/packages/web/src/components/Share.tsx index 22b9c5f8f..3f19b4c80 100644 --- a/app/packages/web/src/components/Share.tsx +++ b/app/packages/web/src/components/Share.tsx @@ -1,4 +1,15 @@ -import { createSignal, onCleanup, onMount, Show, For, createMemo } from "solid-js" +import { + For, + Show, + Match, + Switch, + onMount, + onCleanup, + createMemo, + createSignal, +} from "solid-js" +import { DateTime } from "luxon" +import { IconCpuChip, IconSparkles, IconUserCircle, IconWrenchScrewdriver } from "./icons" import styles from "./share.module.css" import { type UIMessage } from "ai" import { createStore, reconcile } from "solid-js/store" @@ -8,17 +19,17 @@ type Status = "disconnected" | "connecting" | "connected" | "error" | "reconnect type SessionMessage = UIMessage<{ time: { - created: number; - completed?: number; - }; - sessionID: string; + created: number + completed?: number + } + sessionID: string tool: Record<string, { - properties: Record<string, any>; + properties: Record<string, any> time: { - start: number; - end: number; - }; - }>; + start: number + end: number + } + }> }> type SessionInfo = { @@ -41,6 +52,14 @@ function getStatusText(status: [Status, string?]): string { } } +function TextPart(props: { text: string }) { + return ( + <div data-element-message-text> + <pre>{props.text}</pre> + </div> + ) +} + export default function Share(props: { api: string }) { let params = new URLSearchParams(document.location.search) const sessionId = params.get("id") @@ -151,6 +170,16 @@ export default function Share(props: { api: string }) { }) }) + function renderTime(time: number) { + return ( + <span title={ + DateTime.fromMillis(time).toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS) + }> + {DateTime.fromMillis(time).toLocaleString(DateTime.TIME_WITH_SECONDS)} + </span> + ) + } + return ( <main class={`${styles.root} not-content`}> <div class={styles.header}> @@ -158,13 +187,13 @@ export default function Share(props: { api: string }) { <h1>{store.info?.title}</h1> <p> <span data-status={connectionStatus()[0]}>●</span> - <span>{getStatusText(connectionStatus())}</span> + <span data-element-label>{getStatusText(connectionStatus())}</span> </p> </div> <div data-section="row"> - <ul class={styles.stats}> + <ul data-section="stats"> <li> - <span>Input Tokens</span> + <span data-element-label>Input Tokens</span> {store.info?.tokens?.input ? <span>{store.info?.tokens?.input}</span> : @@ -172,7 +201,7 @@ export default function Share(props: { api: string }) { } </li> <li> - <span>Output Tokens</span> + <span data-element-label>Output Tokens</span> {store.info?.tokens?.output ? <span>{store.info?.tokens?.output}</span> : @@ -180,7 +209,7 @@ export default function Share(props: { api: string }) { } </li> <li> - <span>Reasoning Tokens</span> + <span data-element-label>Reasoning Tokens</span> {store.info?.tokens?.reasoning ? <span>{store.info?.tokens?.reasoning}</span> : @@ -188,12 +217,74 @@ export default function Share(props: { api: string }) { } </li> </ul> - <div class={styles.context}> - <button>View Context ></button> + <div data-section="date"> + {messages().length > 0 && messages()[0].metadata?.time.created ? + <span title={ + DateTime.fromMillis( + messages()[0].metadata?.time.created || 0 + ).toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS) + }> + {DateTime.fromMillis( + messages()[0].metadata?.time.created || 0 + ).toLocaleString(DateTime.DATE_MED)} + </span> + : + <span data-element-label data-placeholder>Started at —</span> + } </div> </div> </div> + <div> + <Show + when={messages().length > 0} + fallback={<p>Waiting for messages...</p>} + > + <div class={styles.parts}> + <For each={messages()}> + {(msg) => ( + <For each={msg.parts}> + {(part) => ( + <div + data-section="part" + data-message-role={msg.role} + data-part-type={part.type} + > + <div data-section="decoration"> + <div> + <Switch fallback={ + <IconWrenchScrewdriver width={16} height={16} /> + }> + <Match when={msg.role === "assistant" && (part.type === "text" || part.type === "step-start")}> + <IconSparkles width={18} height={18} /> + </Match> + <Match when={msg.role === "system"}> + <IconCpuChip width={18} height={18} /> + </Match> + <Match when={msg.role === "user"}> + <IconUserCircle width={18} height={18} /> + </Match> + </Switch> + </div> + <div></div> + </div> + <div data-section="content"> + <TextPart text={JSON.stringify(part, null, 2)} /> + {renderTime( + msg.metadata?.time.completed + || msg.metadata?.time.created + || 0 + )} + </div> + </div> + )} + </For> + )} + </For> + </div> + </Show> + </div> + <div style={{ margin: "2rem 0" }}> <div style={{ |
