summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/components
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-12 08:52:51 -0500
committerGitHub <[email protected]>2026-03-12 08:52:51 -0500
commit12efbbfa4c49631f8a0201459a0956f78461b355 (patch)
tree2e6b3e7403ea3564eb8b551ae91035e2d8f7b391 /packages/app/src/components
parent13402529ce1ffb8aabcd4843d76dae41ba8855d4 (diff)
downloadopencode-12efbbfa4c49631f8a0201459a0956f78461b355.tar.gz
opencode-12efbbfa4c49631f8a0201459a0956f78461b355.zip
chore: cleanup (#17184)
Diffstat (limited to 'packages/app/src/components')
-rw-r--r--packages/app/src/components/dialog-select-file.tsx8
-rw-r--r--packages/app/src/components/prompt-input.tsx66
-rw-r--r--packages/app/src/components/session-context-usage.tsx7
-rw-r--r--packages/app/src/components/session/session-context-tab.tsx8
-rw-r--r--packages/app/src/components/session/session-header.tsx11
5 files changed, 28 insertions, 72 deletions
diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx
index b530aff53..9b88cff90 100644
--- a/packages/app/src/components/dialog-select-file.tsx
+++ b/packages/app/src/components/dialog-select-file.tsx
@@ -6,7 +6,7 @@ import { Keybind } from "@opencode-ai/ui/keybind"
import { List } from "@opencode-ai/ui/list"
import { base64Encode } from "@opencode-ai/util/encode"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
-import { useNavigate, useParams } from "@solidjs/router"
+import { useNavigate } from "@solidjs/router"
import { createMemo, createSignal, Match, onCleanup, Show, Switch } from "solid-js"
import { formatKeybind, useCommand, type CommandOption } from "@/context/command"
import { useGlobalSDK } from "@/context/global-sdk"
@@ -14,6 +14,7 @@ import { useGlobalSync } from "@/context/global-sync"
import { useLayout } from "@/context/layout"
import { useFile } from "@/context/file"
import { useLanguage } from "@/context/language"
+import { useSessionLayout } from "@/pages/session/session-layout"
import { decode64 } from "@/utils/base64"
import { getRelativeTime } from "@/utils/time"
@@ -259,14 +260,11 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
const layout = useLayout()
const file = useFile()
const dialog = useDialog()
- const params = useParams()
const navigate = useNavigate()
const globalSDK = useGlobalSDK()
const globalSync = useGlobalSync()
+ const { params, tabs, view } = useSessionLayout()
const filesOnly = () => props.mode === "files"
- const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
- const tabs = createMemo(() => layout.tabs(sessionKey))
- const view = createMemo(() => layout.view(sessionKey))
const state = { cleanup: undefined as (() => void) | void, committed: false }
const [grouped, setGrouped] = createSignal(false)
const commandEntries = createCommandEntries({ filesOnly, command, language })
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
index 3ee8f4351..f1a33e75f 100644
--- a/packages/app/src/components/prompt-input.tsx
+++ b/packages/app/src/components/prompt-input.tsx
@@ -17,7 +17,6 @@ import {
} from "@/context/prompt"
import { useLayout } from "@/context/layout"
import { useSDK } from "@/context/sdk"
-import { useParams } from "@solidjs/router"
import { useSync } from "@/context/sync"
import { useComments } from "@/context/comments"
import { Button } from "@opencode-ai/ui/button"
@@ -37,6 +36,7 @@ import { Persist, persisted } from "@/utils/persist"
import { usePermission } from "@/context/permission"
import { useLanguage } from "@/context/language"
import { usePlatform } from "@/context/platform"
+import { useSessionLayout } from "@/pages/session/session-layout"
import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom"
import { createPromptAttachments, ACCEPTED_FILE_TYPES } from "./prompt-input/attachments"
import {
@@ -102,13 +102,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const prompt = usePrompt()
const layout = useLayout()
const comments = useComments()
- const params = useParams()
const dialog = useDialog()
const providers = useProviders()
const command = useCommand()
const permission = usePermission()
const language = useLanguage()
const platform = usePlatform()
+ const { params, tabs, view } = useSessionLayout()
let editorRef!: HTMLDivElement
let fileInputRef: HTMLInputElement | undefined
let scrollRef!: HTMLDivElement
@@ -154,10 +154,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
requestAnimationFrame(scrollCursorIntoView)
}
- const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
- const tabs = createMemo(() => layout.tabs(sessionKey))
- const view = createMemo(() => layout.view(sessionKey))
-
const commentInReview = (path: string) => {
const sessionID = params.id
if (!sessionID) return false
@@ -255,6 +251,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
})
const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 })
+ const motion = (value: number) => ({
+ opacity: value,
+ transform: `scale(${0.95 + value * 0.05})`,
+ filter: `blur(${(1 - value) * 2}px)`,
+ "pointer-events": value > 0.5 ? ("auto" as const) : ("none" as const),
+ })
+ const buttons = createMemo(() => motion(buttonsSpring()))
+ const shell = createMemo(() => motion(1 - buttonsSpring()))
+ const control = createMemo(() => ({ height: "28px", ...buttons() }))
const commentCount = createMemo(() => {
if (store.mode === "shell") return 0
@@ -1275,11 +1280,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
type="button"
variant="ghost"
class="size-8 p-0"
- style={{
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- }}
+ style={buttons()}
onClick={pick}
disabled={store.mode !== "normal"}
tabIndex={store.mode === "normal" ? undefined : -1}
@@ -1317,11 +1318,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
icon={working() ? "stop" : "arrow-up"}
variant="primary"
class="size-8"
- style={{
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- }}
+ style={buttons()}
aria-label={working() ? language.t("prompt.action.stop") : language.t("prompt.action.send")}
/>
</Tooltip>
@@ -1379,10 +1376,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
class="h-7 flex items-center gap-1.5 max-w-[160px] min-w-0 absolute inset-y-0 left-0"
style={{
padding: "0 4px 0 8px",
- opacity: 1 - buttonsSpring(),
- transform: `scale(${0.95 + (1 - buttonsSpring()) * 0.05})`,
- filter: `blur(${buttonsSpring() * 2}px)`,
- "pointer-events": buttonsSpring() < 0.5 ? "auto" : "none",
+ ...shell(),
}}
>
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
@@ -1402,13 +1396,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
onSelect={local.agent.set}
class="capitalize max-w-[160px]"
valueClass="truncate text-13-regular"
- triggerStyle={{
- height: "28px",
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none",
- }}
+ triggerStyle={control()}
variant="ghost"
/>
</TooltipKeybind>
@@ -1426,13 +1414,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
variant="ghost"
size="normal"
class="min-w-0 max-w-[320px] text-13-regular group"
- style={{
- height: "28px",
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none",
- }}
+ style={control()}
onClick={() => dialog.show(() => <DialogSelectModelUnpaid />)}
>
<Show when={local.model.current()?.provider?.id}>
@@ -1461,13 +1443,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
triggerProps={{
variant: "ghost",
size: "normal",
- style: {
- height: "28px",
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none",
- },
+ style: control(),
class: "min-w-0 max-w-[320px] text-13-regular group",
}}
>
@@ -1499,13 +1475,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
onSelect={(x) => local.model.variant.set(x === "default" ? undefined : x)}
class="capitalize max-w-[160px]"
valueClass="truncate text-13-regular"
- triggerStyle={{
- height: "28px",
- opacity: buttonsSpring(),
- transform: `scale(${0.95 + buttonsSpring() * 0.05})`,
- filter: `blur(${(1 - buttonsSpring()) * 2}px)`,
- "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none",
- }}
+ triggerStyle={control()}
variant="ghost"
/>
</TooltipKeybind>
diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx
index 08ae4d319..99e6c13a3 100644
--- a/packages/app/src/components/session-context-usage.tsx
+++ b/packages/app/src/components/session-context-usage.tsx
@@ -2,12 +2,12 @@ import { Match, Show, Switch, createMemo } from "solid-js"
import { Tooltip, type TooltipProps } from "@opencode-ai/ui/tooltip"
import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
import { Button } from "@opencode-ai/ui/button"
-import { useParams } from "@solidjs/router"
import { useLayout } from "@/context/layout"
import { useSync } from "@/context/sync"
import { useLanguage } from "@/context/language"
import { getSessionContextMetrics } from "@/components/session/session-context-metrics"
+import { useSessionLayout } from "@/pages/session/session-layout"
interface SessionContextUsageProps {
variant?: "button" | "indicator"
@@ -27,14 +27,11 @@ function openSessionContext(args: {
export function SessionContextUsage(props: SessionContextUsageProps) {
const sync = useSync()
- const params = useParams()
const layout = useLayout()
const language = useLanguage()
+ const { params, tabs, view } = useSessionLayout()
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(
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx
index 39eb4b4c0..9aa101bdb 100644
--- a/packages/app/src/components/session/session-context-tab.tsx
+++ b/packages/app/src/components/session/session-context-tab.tsx
@@ -1,8 +1,6 @@
import { createMemo, createEffect, on, onCleanup, For, Show } from "solid-js"
import type { JSX } from "solid-js"
-import { useParams } from "@solidjs/router"
import { useSync } from "@/context/sync"
-import { useLayout } from "@/context/layout"
import { checksum } from "@opencode-ai/util/encode"
import { findLast } from "@opencode-ai/util/array"
import { same } from "@/utils/same"
@@ -14,6 +12,7 @@ import { Markdown } from "@opencode-ai/ui/markdown"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
import type { Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client"
import { useLanguage } from "@/context/language"
+import { useSessionLayout } from "@/pages/session/session-layout"
import { getSessionContextMetrics } from "./session-context-metrics"
import { estimateSessionContextBreakdown, type SessionContextBreakdownKey } from "./session-context-breakdown"
import { createSessionContextFormatter } from "./session-context-format"
@@ -91,13 +90,10 @@ const emptyMessages: Message[] = []
const emptyUserMessages: UserMessage[] = []
export function SessionContextTab() {
- const params = useParams()
const sync = useSync()
- const layout = useLayout()
const language = useLanguage()
+ const { params, view } = useSessionLayout()
- const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
- const view = createMemo(() => layout.view(sessionKey))
const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
const messages = createMemo(
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index 97f0530e9..9476f8b9b 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -10,7 +10,6 @@ import { TextField } from "@opencode-ai/ui/text-field"
import { showToast } from "@opencode-ai/ui/toast"
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
import { getFilename } from "@opencode-ai/util/path"
-import { useParams } from "@solidjs/router"
import { createEffect, createMemo, For, onCleanup, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { Portal } from "solid-js/web"
@@ -23,6 +22,7 @@ import { useServer } from "@/context/server"
import { useSync } from "@/context/sync"
import { useTerminal } from "@/context/terminal"
import { focusTerminalById } from "@/pages/session/helpers"
+import { useSessionLayout } from "@/pages/session/session-layout"
import { decode64 } from "@/utils/base64"
import { Persist, persisted } from "@/utils/persist"
import { StatusPopover } from "../status-popover"
@@ -225,13 +225,13 @@ function useSessionShare(args: {
export function SessionHeader() {
const globalSDK = useGlobalSDK()
const layout = useLayout()
- const params = useParams()
const command = useCommand()
const server = useServer()
const sync = useSync()
const platform = usePlatform()
const language = useLanguage()
const terminal = useTerminal()
+ const { params, view } = useSessionLayout()
const projectDirectory = createMemo(() => decode64(params.dir) ?? "")
const project = createMemo(() => {
@@ -249,8 +249,6 @@ export function SessionHeader() {
const currentSession = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
const showShare = createMemo(() => shareEnabled() && !!params.id)
- const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
- const view = createMemo(() => layout.view(sessionKey))
const os = createMemo(() => detectOS(platform))
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
@@ -282,10 +280,7 @@ export function SessionHeader() {
Promise.resolve(platform.checkAppExists?.(app.openWith))
.then((value) => Boolean(value))
.catch(() => false)
- .then((ok) => {
- console.debug(`[session-header] App "${app.label}" (${app.openWith}): ${ok ? "exists" : "does not exist"}`)
- return [app.id, ok] as const
- }),
+ .then((ok) => [app.id, ok] as const),
),
).then((entries) => {
setExists(Object.fromEntries(entries) as Partial<Record<OpenApp, boolean>>)