Compare commits

...

3 Commits

Author SHA1 Message Date
usrnk1 04017a9172 sidepanel interaction fix 2026-06-29 13:34:42 +02:00
usrnk1 b32526bd76 fix intermittent double-click on context menu button 2026-06-29 13:16:07 +02:00
usrnk1 9b76dc4e06 use v2 styles 2026-06-29 13:10:06 +02:00
3 changed files with 54 additions and 24 deletions
@@ -1,11 +1,10 @@
import { Match, Show, Switch, createMemo } from "solid-js"
import { Match, Show, Switch, createEffect, createMemo } from "solid-js"
import { Tooltip, type TooltipProps } from "@opencode-ai/ui/tooltip"
import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
import { ProgressCircleV2 } from "@opencode-ai/ui/v2/progress-circle-v2"
import { Button } from "@opencode-ai/ui/button"
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
import { useFile } from "@/context/file"
import { useLayout } from "@/context/layout"
import { useSync } from "@/context/sync"
import { useLanguage } from "@/context/language"
@@ -13,7 +12,6 @@ import { useProviders } from "@/hooks/use-providers"
import { useSDK } from "@/context/sdk"
import { getSessionContext, getSessionTokenTotal } from "@/components/session/session-context-metrics"
import { useSessionLayout } from "@/pages/session/session-layout"
import { createSessionTabs } from "@/pages/session/helpers"
interface SessionContextUsageProps {
variant?: "button" | "indicator"
@@ -34,7 +32,6 @@ function openSessionContext(args: {
export function SessionContextUsage(props: SessionContextUsageProps) {
const sync = useSync()
const file = useFile()
const layout = useLayout()
const language = useLanguage()
const sdk = useSDK()
@@ -43,11 +40,6 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
const variant = createMemo(() => props.variant ?? "button")
const buttonAppearance = createMemo(() => props.buttonAppearance ?? "default")
const tabState = createSessionTabs({
tabs,
pathFromTab: file.pathFromTab,
normalizeTab: (tab) => (tab.startsWith("file://") ? file.tab(tab) : tab),
})
const messages = createMemo(() => (params.id ? (sync().data.message[params.id] ?? []) : []))
const info = createMemo(() => (params.id ? sync().session.get(params.id) : undefined))
@@ -65,15 +57,27 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
return usd().format(info()?.cost ?? 0)
})
let openedPanelWithContext = false
createEffect(() => {
if (!view().reviewPanel.opened()) openedPanelWithContext = false
})
const openContext = () => {
if (!params.id) return
if (tabState.activeTab() === "context") {
const sessionView = view()
if (sessionView.reviewPanel.opened() && tabs().active() === "context") {
const hasOtherTabs = tabs().all().some((tab) => tab !== "context" && tab !== "review")
tabs().close("context")
if (openedPanelWithContext && !hasOtherTabs) sessionView.reviewPanel.close()
openedPanelWithContext = false
return
}
openedPanelWithContext = !sessionView.reviewPanel.opened()
openSessionContext({
view: view(),
view: sessionView,
layout,
tabs: tabs(),
})
@@ -81,7 +85,20 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
const circle = () => (
<div class="flex items-center justify-center">
<ProgressCircle size={16} strokeWidth={2} percentage={context()?.usage ?? 0} />
<ProgressCircle
size={16}
strokeWidth={2}
percentage={context()?.usage ?? 0}
style={
variant() === "indicator"
? {
"--progress-circle-background": "var(--v2-background-bg-layer-04, var(--border-weak-base))",
"--progress-circle-background-overlay": "var(--v2-overlay-simple-overlay-pressed, transparent)",
"--progress-circle-progress": "var(--v2-icon-icon-base, var(--icon-base))",
}
: undefined
}
/>
</div>
)
const circleV2 = () => (
@@ -119,10 +136,10 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
return (
<Show when={params.id}>
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
<Switch>
<Match when={variant() === "indicator"}>{circle()}</Match>
<Match when={buttonAppearance() === "v2"}>
<Switch>
<Match when={variant() === "indicator"}>{circle()}</Match>
<Match when={buttonAppearance() === "v2"}>
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
<IconButtonV2
type="button"
variant="ghost-muted"
@@ -131,8 +148,10 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
onClick={openContext}
aria-label={language.t("context.usage.view")}
/>
</Match>
<Match when={true}>
</Tooltip>
</Match>
<Match when={true}>
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
<Button
type="button"
variant="ghost"
@@ -142,9 +161,9 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
>
{circle()}
</Button>
</Match>
</Switch>
</Tooltip>
</Tooltip>
</Match>
</Switch>
</Show>
)
}
@@ -2,11 +2,15 @@
transform: rotate(-90deg);
[data-slot="progress-circle-background"] {
stroke: var(--border-weak-base);
stroke: var(--progress-circle-background, var(--border-weak-base));
}
[data-slot="progress-circle-background-overlay"] {
stroke: var(--progress-circle-background-overlay, transparent);
}
[data-slot="progress-circle-progress"] {
stroke: var(--border-active);
stroke: var(--progress-circle-progress, var(--border-active));
transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
}
@@ -1,6 +1,6 @@
import { type ComponentProps, createMemo, splitProps } from "solid-js"
export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class" | "classList"> {
export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class" | "classList" | "style"> {
percentage: number
size?: number
strokeWidth?: number
@@ -43,6 +43,13 @@ export function ProgressCircle(props: ProgressCircleProps) {
data-slot="progress-circle-background"
stroke-width={strokeWidth()}
/>
<circle
cx={center}
cy={center}
r={radius()}
data-slot="progress-circle-background-overlay"
stroke-width={strokeWidth()}
/>
<circle
cx={center}
cy={center}