diff --git a/packages/app/e2e/file-tree.spec.ts b/packages/app/e2e/file-tree.spec.ts index c22a810f4f0..b56667049a4 100644 --- a/packages/app/e2e/file-tree.spec.ts +++ b/packages/app/e2e/file-tree.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from "./fixtures" test("file tree can expand folders and open a file", async ({ page, gotoSession }) => { await gotoSession() - const toggle = page.getByRole("button", { name: "Toggle file tree" }) + const toggle = page.getByRole("button", { name: "Toggle review" }) const treeTabs = page.locator('[data-component="tabs"][data-variant="pill"][data-scope="filetree"]') if ((await toggle.getAttribute("aria-expanded")) !== "true") await toggle.click() diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx index 1e37d8f6a20..6295b3012ee 100644 --- a/packages/app/src/components/session-context-usage.tsx +++ b/packages/app/src/components/session-context-usage.tsx @@ -1,4 +1,4 @@ -import { Match, Show, Switch, createMemo } from "solid-js" +import { Match, Show, Switch, createMemo, createSignal, onCleanup } from "solid-js" import { Tooltip } from "@opencode-ai/ui/tooltip" import { ProgressCircle } from "@opencode-ai/ui/progress-circle" import { Button } from "@opencode-ai/ui/button" @@ -14,15 +14,22 @@ interface SessionContextUsageProps { variant?: "button" | "indicator" } +const isTouch = () => window.matchMedia("(hover: none)").matches + export function SessionContextUsage(props: SessionContextUsageProps) { const sync = useSync() const params = useParams() const layout = useLayout() const language = useLanguage() + const [touchTooltip, setTouchTooltip] = createSignal(false) + let tooltipTimer: number | undefined + + onCleanup(() => clearTimeout(tooltipTimer)) const variant = createMemo(() => props.variant ?? "button") const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey)) + const view = createMemo(() => layout.view(sessionKey)) const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : [])) const usd = createMemo( @@ -57,12 +64,32 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const openContext = () => { if (!params.id) return - layout.fileTree.open() layout.fileTree.setTab("all") + layout.fileTree.open() + view().mobileTab.set("context") tabs().open("context") tabs().setActive("context") } + const handleClick = () => { + if (variant() === "indicator") return + if (isTouch() && !touchTooltip()) { + setTouchTooltip(true) + clearTimeout(tooltipTimer) + tooltipTimer = window.setTimeout(() => setTouchTooltip(false), 3000) + return + } + setTouchTooltip(false) + openContext() + } + + const handleOpenChange = (open: boolean) => { + // On touch devices, we control the tooltip state ourselves via handleClick + // Ignore Kobalte's attempts to close it + if (isTouch()) return + setTouchTooltip(open) + } + const circle = () => (