diff --git a/packages/desktop/src/app.tsx b/packages/desktop/src/app.tsx index 789a8fa2d..be31a594e 100644 --- a/packages/desktop/src/app.tsx +++ b/packages/desktop/src/app.tsx @@ -5,7 +5,9 @@ import { MetaProvider } from "@solidjs/meta" import { Font } from "@opencode-ai/ui/font" import { MarkedProvider } from "@opencode-ai/ui/context/marked" import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" +import { CodeComponentProvider } from "@opencode-ai/ui/context/code" import { Diff } from "@opencode-ai/ui/diff" +import { Code } from "@opencode-ai/ui/code" import { GlobalSyncProvider } from "@/context/global-sync" import { LayoutProvider } from "@/context/layout" import { GlobalSDKProvider } from "@/context/global-sdk" @@ -39,41 +41,43 @@ export function App() { - - - - - - - ( - - {props.children} - - )} - > - - - } /> - ( - - - - - - - - )} - /> - - - - - - - + + + + + + + + ( + + {props.children} + + )} + > + + + } /> + ( + + + + + + + + )} + /> + + + + + + + + diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 390872d36..1b23ad5f2 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -1,4 +1,5 @@ import { For, onCleanup, onMount, Show, Match, Switch, createResource, createMemo, createEffect, on } from "solid-js" +import { Dynamic } from "solid-js/web" import { useLocal, type LocalFile } from "@/context/local" import { createStore } from "solid-js/store" import { PromptInput } from "@/components/prompt-input" @@ -11,7 +12,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { ProgressCircle } from "@opencode-ai/ui/progress-circle" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Tabs } from "@opencode-ai/ui/tabs" -import { Code } from "@opencode-ai/ui/code" +import { useCodeComponent } from "@opencode-ai/ui/context/code" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { SessionMessageRail } from "@opencode-ai/ui/session-message-rail" import { SessionReview } from "@opencode-ai/ui/session-review" @@ -48,6 +49,7 @@ export default function Page() { const sync = useSync() const terminal = useTerminal() const dialog = useDialog() + const codeComponent = useCodeComponent() const command = useCommand() const params = useParams() const navigate = useNavigate() @@ -764,7 +766,8 @@ export default function Page() { {(f) => ( - import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) +const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) const SessionDataMissingError = NamedError.create( "SessionDataMissingError", @@ -196,239 +198,254 @@ export default function () { - - {iife(() => { - const [store, setStore] = createStore({ - messageId: undefined as string | undefined, - }) - const messages = createMemo(() => - data().sessionID - ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( - (a, b) => a.time.created - b.time.created, - ) - : [], - ) - const firstUserMessage = createMemo(() => messages().at(0)) - const activeMessage = createMemo( - () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), - ) - function setActiveMessage(message: UserMessage | undefined) { - if (message) { - setStore("messageId", message.id) - } else { - setStore("messageId", undefined) + + + {iife(() => { + const [store, setStore] = createStore({ + messageId: undefined as string | undefined, + }) + const messages = createMemo(() => + data().sessionID + ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( + (a, b) => a.time.created - b.time.created, + ) + : [], + ) + const firstUserMessage = createMemo(() => messages().at(0)) + const activeMessage = createMemo( + () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), + ) + function setActiveMessage(message: UserMessage | undefined) { + if (message) { + setStore("messageId", message.id) + } else { + setStore("messageId", undefined) + } } - } - const provider = createMemo(() => activeMessage()?.model?.providerID) - const modelID = createMemo(() => activeMessage()?.model?.modelID) - const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) - const diffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) - const splitDiffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload_split[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) + const provider = createMemo(() => activeMessage()?.model?.providerID) + const modelID = createMemo(() => activeMessage()?.model?.modelID) + const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) + const diffs = createMemo(() => { + const diffs = data().session_diff[data().sessionID] ?? [] + const preloaded = data().session_diff_preload[data().sessionID] ?? [] + return diffs.map((diff) => ({ + ...diff, + preloaded: preloaded.find((d) => d.newFile.name === diff.file), + })) + }) + const splitDiffs = createMemo(() => { + const diffs = data().session_diff[data().sessionID] ?? [] + const preloaded = data().session_diff_preload_split[data().sessionID] ?? [] + return diffs.map((diff) => ({ + ...diff, + preloaded: preloaded.find((d) => d.newFile.name === diff.file), + })) + }) - const title = () => ( -
-
-
- -
v{info().version}
-
-
- -
{model()?.name ?? modelID()}
-
-
- {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
-
-
{info().title}
-
- ) - - const turns = () => ( -
-
{title()}
-
- - {(message) => ( - ( +
+
+
+ +
v{info().version}
+
+
+ - )} - -
-
- -
-
- ) - - const wide = createMemo(() => diffs().length === 0) - - return ( -
-
-
- - - +
{model()?.name ?? modelID()}
+
+
+ {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} +
-
- - +
{info().title}
+
+ ) + + const turns = () => ( +
+
{title()}
+
+ + {(message) => ( + + )} +
- -
-
+
+ +
+
+ ) + + const wide = createMemo(() => diffs().length === 0) + + return ( +
+
+
+ + + +
+
+ + +
+
+
1, - "px-6": !wide() && messages().length === 1, + "@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true, + "mx-auto max-w-146": !wide(), }} > - {title()} -
-
- - 1 - ? "pr-6 pl-18" - : "px-6"), +
1, + "px-6": !wide() && messages().length === 1, }} > -
- -
- -
-
- 0}> - -
- -
+
+ + 1 + ? "pr-6 pl-18" + : "px-6"), + }} + > +
+ +
+
-
-
-
- - 0}> - - - - Session - - - {diffs().length} Files Changed - - - - {turns()} - - - - - -
- {turns()}
-
-
+ 0}> + +
+ +
+
+
+
+ + 0}> + + + + Session + + + {diffs().length} Files Changed + + + + {turns()} + + + + + +
+ {turns()} +
+
+
+
-
- ) - })} - + ) + })} + + ) diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 33b519ea4..b838bebc2 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -11,6 +11,7 @@ import { } from "@opencode-ai/sdk/v2" import { useData } from "../context" import { useDiffComponent } from "../context/diff" +import { useCodeComponent } from "../context/code" import { BasicTool } from "./basic-tool" import { GenericTool } from "./basic-tool" import { Card } from "./card" @@ -19,6 +20,7 @@ import { Checkbox } from "./checkbox" import { DiffChanges } from "./diff-changes" import { Markdown } from "./markdown" import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path" +import { checksum } from "@opencode-ai/util/encode" export interface MessageProps { message: MessageType @@ -488,9 +490,10 @@ ToolRegistry.register({ ToolRegistry.register({ name: "write", render(props) { - console.log(props) + const codeComponent = useCodeComponent() return ( @@ -507,19 +510,19 @@ ToolRegistry.register({
} > - {/* */} - {/*
*/} - {/* */} - {/*
*/} - {/*
*/} + +
+ +
+
) }, diff --git a/packages/ui/src/context/code.tsx b/packages/ui/src/context/code.tsx new file mode 100644 index 000000000..3a2511527 --- /dev/null +++ b/packages/ui/src/context/code.tsx @@ -0,0 +1,10 @@ +import type { ValidComponent } from "solid-js" +import { createSimpleContext } from "./helper" + +const ctx = createSimpleContext({ + name: "CodeComponent", + init: (props) => props.component, +}) + +export const CodeComponentProvider = ctx.provider +export const useCodeComponent = ctx.use diff --git a/packages/ui/src/context/diff.tsx b/packages/ui/src/context/diff.tsx index 630437de6..747de9cc8 100644 --- a/packages/ui/src/context/diff.tsx +++ b/packages/ui/src/context/diff.tsx @@ -1,13 +1,10 @@ -import { createContext, useContext, type ParentProps, type ValidComponent } from "solid-js" +import type { ValidComponent } from "solid-js" +import { createSimpleContext } from "./helper" -const DiffComponentContext = createContext() +const ctx = createSimpleContext({ + name: "DiffComponent", + init: (props) => props.component, +}) -export function DiffComponentProvider(props: ParentProps<{ component: ValidComponent }>) { - return {props.children} -} - -export function useDiffComponent() { - const component = useContext(DiffComponentContext) - if (!component) throw new Error("DiffComponentProvider must be used to provide a diff component") - return component -} +export const DiffComponentProvider = ctx.provider +export const useDiffComponent = ctx.use