diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index 7070f0c9337..96ed762c448 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -1,15 +1,17 @@
-import { createMemo, createResource, Show } from "solid-js"
+import { createEffect, createMemo, onCleanup, Show } from "solid-js"
+import { createStore } from "solid-js/store"
import { Portal } from "solid-js/web"
import { useParams } from "@solidjs/router"
import { useLayout } from "@/context/layout"
import { useCommand } from "@/context/command"
// import { useServer } from "@/context/server"
// import { useDialog } from "@opencode-ai/ui/context/dialog"
+import { usePlatform } from "@/context/platform"
import { useSync } from "@/context/sync"
import { useGlobalSDK } from "@/context/global-sdk"
import { getFilename } from "@opencode-ai/util/path"
import { base64Decode } from "@opencode-ai/util/encode"
-import { iife } from "@opencode-ai/util/iife"
+
import { Icon } from "@opencode-ai/ui/icon"
import { IconButton } from "@opencode-ai/ui/icon-button"
import { Button } from "@opencode-ai/ui/button"
@@ -26,6 +28,7 @@ export function SessionHeader() {
// const server = useServer()
// const dialog = useDialog()
const sync = useSync()
+ const platform = usePlatform()
const projectDirectory = createMemo(() => base64Decode(params.dir ?? ""))
const project = createMemo(() => {
@@ -45,6 +48,78 @@ export function SessionHeader() {
const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
const view = createMemo(() => layout.view(sessionKey()))
+ const [state, setState] = createStore({
+ share: false,
+ unshare: false,
+ copied: false,
+ timer: undefined as number | undefined,
+ })
+ const shareUrl = createMemo(() => currentSession()?.share?.url)
+
+ createEffect(() => {
+ const url = shareUrl()
+ if (url) return
+ if (state.timer) window.clearTimeout(state.timer)
+ setState({ copied: false, timer: undefined })
+ })
+
+ onCleanup(() => {
+ if (state.timer) window.clearTimeout(state.timer)
+ })
+
+ function shareSession() {
+ const session = currentSession()
+ if (!session || state.share) return
+ setState("share", true)
+ globalSDK.client.session
+ .share({ sessionID: session.id, directory: projectDirectory() })
+ .catch((error) => {
+ console.error("Failed to share session", error)
+ })
+ .finally(() => {
+ setState("share", false)
+ })
+ }
+
+ function unshareSession() {
+ const session = currentSession()
+ if (!session || state.unshare) return
+ setState("unshare", true)
+ globalSDK.client.session
+ .unshare({ sessionID: session.id, directory: projectDirectory() })
+ .catch((error) => {
+ console.error("Failed to unshare session", error)
+ })
+ .finally(() => {
+ setState("unshare", false)
+ })
+ }
+
+ function copyLink() {
+ const url = shareUrl()
+ if (!url) return
+ navigator.clipboard
+ .writeText(url)
+ .then(() => {
+ if (state.timer) window.clearTimeout(state.timer)
+ setState("copied", true)
+ const timer = window.setTimeout(() => {
+ setState("copied", false)
+ setState("timer", undefined)
+ }, 3000)
+ setState("timer", timer)
+ })
+ .catch((error) => {
+ console.error("Failed to copy share link", error)
+ })
+ }
+
+ function viewShare() {
+ const url = shareUrl()
+ if (!url) return
+ platform.openLink(url)
+ }
+
const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center"))
const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right"))
@@ -58,14 +133,14 @@ export function SessionHeader() {
class="hidden md:flex w-[320px] p-1 pl-1.5 items-center gap-2 justify-between rounded-md border border-border-weak-base bg-surface-raised-base transition-colors cursor-default hover:bg-surface-raised-base-hover focus:bg-surface-raised-base-hover active:bg-surface-raised-base-active"
onClick={() => command.trigger("file.open")}
>
-
-
-
+
+
+
Search {name()}
- {(keybind) => {keybind()}}
+ {(keybind) => {keybind()}}
)}
@@ -159,40 +234,77 @@ export function SessionHeader() {
-
-
-
- }
- >
- {iife(() => {
- const [url] = createResource(
- () => currentSession(),
- async (session) => {
- if (!session) return
- let shareURL = session.share?.url
- if (!shareURL) {
- shareURL = await globalSDK.client.session
- .share({ sessionID: session.id, directory: projectDirectory() })
- .then((r) => r.data?.share?.url)
- .catch((e) => {
- console.error("Failed to share session", e)
- return undefined
- })
+
+
+
+
+ }
+ >
+
+
+
+
}
- return shareURL
- },
- { initialValue: "" },
- )
- return (
-
- {(shareUrl) => }
+ >
+
+
+
+
+
+
+
- )
- })}
-
+
+
+
+
+
+
+
+