summaryrefslogtreecommitdiffhomepage
path: root/packages/web/src/components/Share.tsx
diff options
context:
space:
mode:
authorJay V <[email protected]>2025-06-05 13:52:39 -0400
committerJay V <[email protected]>2025-06-05 13:52:44 -0400
commit142056e9afa6913a44e65bf109eac0c857b49b02 (patch)
treef893d98b071fa6650773f6fc59ee62bca52256d0 /packages/web/src/components/Share.tsx
parent241c366164496f1961a86ae02d2b51e9a9453b12 (diff)
downloadopencode-142056e9afa6913a44e65bf109eac0c857b49b02.tar.gz
opencode-142056e9afa6913a44e65bf109eac0c857b49b02.zip
share page todos
Diffstat (limited to 'packages/web/src/components/Share.tsx')
-rw-r--r--packages/web/src/components/Share.tsx120
1 files changed, 120 insertions, 0 deletions
diff --git a/packages/web/src/components/Share.tsx b/packages/web/src/components/Share.tsx
index b6bd7fd0d..9831504c8 100644
--- a/packages/web/src/components/Share.tsx
+++ b/packages/web/src/components/Share.tsx
@@ -16,6 +16,7 @@ import { IconOpenAI, IconGemini, IconAnthropic } from "./icons/custom"
import {
IconCpuChip,
IconSparkles,
+ IconQueueList,
IconUserCircle,
IconChevronDown,
IconCommandLine,
@@ -75,6 +76,27 @@ type SessionInfo = {
cost?: number
}
+type TodoStatus = "pending" | "in_progress" | "completed"
+
+interface Todo {
+ id: string
+ content: string
+ status: TodoStatus
+ priority: "low" | "medium" | "high"
+}
+
+function sortTodosByStatus(todos: Todo[]) {
+ const statusPriority: Record<TodoStatus, number> = {
+ in_progress: 0,
+ pending: 1,
+ completed: 2,
+ }
+
+ return todos
+ .slice()
+ .sort((a, b) => statusPriority[a.status] - statusPriority[b.status])
+}
+
function getFileType(path: string) {
return path.split(".").pop()
}
@@ -1163,6 +1185,104 @@ export default function Share(props: { api: string }) {
)
}}
</Match>
+ {/* Todo read */}
+ <Match
+ when={
+ msg.role === "assistant" &&
+ part.type === "tool-invocation" &&
+ part.toolInvocation.toolName === "opencode_todoread" &&
+ part
+ }
+ >
+ {(part) => {
+ const metadata = createMemo(() => msg.metadata?.tool[part().toolInvocation.toolCallId])
+
+ 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-fallback"
+ >
+ <div data-section="decoration">
+ <div title="Plan">
+ <IconQueueList width={18} height={18} />
+ </div>
+ <div></div>
+ </div>
+ <div data-section="content">
+ <div data-part-tool-body>
+ <span data-part-title data-size="sm">
+ Checking plan&hellip;
+ </span>
+ </div>
+ <ToolFooter time={duration()} />
+ </div>
+ </div>
+ )
+ }}
+ </Match>
+ {/* Todo write */}
+ <Match
+ when={
+ msg.role === "assistant" &&
+ part.type === "tool-invocation" &&
+ part.toolInvocation.toolName === "opencode_todowrite" &&
+ part
+ }
+ >
+ {(part) => {
+ const metadata = createMemo(() => msg.metadata?.tool[part().toolInvocation.toolCallId])
+
+ const todos = createMemo(() => sortTodosByStatus(
+ part().toolInvocation.args.todos
+ ))
+
+ 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-fallback"
+ >
+ <div data-section="decoration">
+ <div title="Plan">
+ <IconQueueList width={18} height={18} />
+ </div>
+ <div></div>
+ </div>
+ <div data-section="content">
+ <div data-part-tool-body>
+ <span data-part-title data-size="sm">
+ Planning&hellip;
+ </span>
+ <Show when={todos().length > 0}>
+ <ul class={styles.todos}>
+ <For each={todos()}>
+ {({ status, content }) =>
+ <li data-status={status}>
+ <span></span>
+ {content}
+ </li>
+ }
+ </For>
+ </ul>
+ </Show>
+ </div>
+ <ToolFooter time={duration()} />
+ </div>
+ </div>
+ )
+ }}
+ </Match>
{/* Tool call */}
<Match
when={