summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context/layout.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-02 10:50:50 -0600
committerGitHub <[email protected]>2026-03-02 10:50:50 -0600
commit8176bafc555e562ade48a675dffa3f38751ed8c9 (patch)
tree7d4b0f6e98f431999b89c1f24687f6f53bd0bc6b /packages/app/src/context/layout.tsx
parent0a3a3216db5974efd3edc9a213054fd97d8dbd34 (diff)
downloadopencode-8176bafc555e562ade48a675dffa3f38751ed8c9.tar.gz
opencode-8176bafc555e562ade48a675dffa3f38751ed8c9.zip
chore(app): solidjs refactoring (#13399)
Diffstat (limited to 'packages/app/src/context/layout.tsx')
-rw-r--r--packages/app/src/context/layout.tsx82
1 files changed, 77 insertions, 5 deletions
diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx
index 71f0294e7..5199e5a26 100644
--- a/packages/app/src/context/layout.tsx
+++ b/packages/app/src/context/layout.tsx
@@ -7,8 +7,10 @@ import { useServer } from "./server"
import { usePlatform } from "./platform"
import { Project } from "@opencode-ai/sdk/v2"
import { Persist, persisted, removePersisted } from "@/utils/persist"
+import { decode64 } from "@/utils/base64"
import { same } from "@/utils/same"
import { createScrollPersistence, type SessionScroll } from "./layout-scroll"
+import { createPathHelpers } from "./file/path"
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
const DEFAULT_PANEL_WIDTH = 344
@@ -96,6 +98,38 @@ function nextSessionTabsForOpen(current: SessionTabs | undefined, tab: string):
return { all, active: tab }
}
+const sessionPath = (key: string) => {
+ const dir = key.split("/")[0]
+ if (!dir) return
+ const root = decode64(dir)
+ if (!root) return
+ return createPathHelpers(() => root)
+}
+
+const normalizeSessionTab = (path: ReturnType<typeof createPathHelpers> | undefined, tab: string) => {
+ if (!tab.startsWith("file://")) return tab
+ if (!path) return tab
+ return path.tab(tab)
+}
+
+const normalizeSessionTabList = (path: ReturnType<typeof createPathHelpers> | undefined, all: string[]) => {
+ const seen = new Set<string>()
+ return all.flatMap((tab) => {
+ const value = normalizeSessionTab(path, tab)
+ if (seen.has(value)) return []
+ seen.add(value)
+ return [value]
+ })
+}
+
+const normalizeStoredSessionTabs = (key: string, tabs: SessionTabs) => {
+ const path = sessionPath(key)
+ return {
+ all: normalizeSessionTabList(path, tabs.all),
+ active: tabs.active ? normalizeSessionTab(path, tabs.active) : tabs.active,
+ }
+}
+
export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
name: "Layout",
init: () => {
@@ -147,12 +181,46 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
}
})()
- if (migratedSidebar === sidebar && migratedReview === review && migratedFileTree === fileTree) return value
+ const sessionTabs = value.sessionTabs
+ const migratedSessionTabs = (() => {
+ if (!isRecord(sessionTabs)) return sessionTabs
+
+ let changed = false
+ const next = Object.fromEntries(
+ Object.entries(sessionTabs).map(([key, tabs]) => {
+ if (!isRecord(tabs) || !Array.isArray(tabs.all)) return [key, tabs]
+
+ const current = {
+ all: tabs.all.filter((tab): tab is string => typeof tab === "string"),
+ active: typeof tabs.active === "string" ? tabs.active : undefined,
+ }
+ const normalized = normalizeStoredSessionTabs(key, current)
+ if (current.all.length !== tabs.all.length) changed = true
+ if (!same(current.all, normalized.all) || current.active !== normalized.active) changed = true
+ if (tabs.active !== undefined && typeof tabs.active !== "string") changed = true
+ return [key, normalized]
+ }),
+ )
+
+ if (!changed) return sessionTabs
+ return next
+ })()
+
+ if (
+ migratedSidebar === sidebar &&
+ migratedReview === review &&
+ migratedFileTree === fileTree &&
+ migratedSessionTabs === sessionTabs
+ ) {
+ return value
+ }
+
return {
...value,
sidebar: migratedSidebar,
review: migratedReview,
fileTree: migratedFileTree,
+ sessionTabs: migratedSessionTabs,
}
}
@@ -745,22 +813,26 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
},
tabs(sessionKey: string | Accessor<string>) {
const key = createSessionKeyReader(sessionKey, ensureKey)
+ const path = createMemo(() => sessionPath(key()))
const tabs = createMemo(() => store.sessionTabs[key()] ?? { all: [] })
+ const normalize = (tab: string) => normalizeSessionTab(path(), tab)
+ const normalizeAll = (all: string[]) => normalizeSessionTabList(path(), all)
return {
tabs,
active: createMemo(() => tabs().active),
all: createMemo(() => tabs().all.filter((tab) => tab !== "review")),
setActive(tab: string | undefined) {
const session = key()
+ const next = tab ? normalize(tab) : tab
if (!store.sessionTabs[session]) {
- setStore("sessionTabs", session, { all: [], active: tab })
+ setStore("sessionTabs", session, { all: [], active: next })
} else {
- setStore("sessionTabs", session, "active", tab)
+ setStore("sessionTabs", session, "active", next)
}
},
setAll(all: string[]) {
const session = key()
- const next = all.filter((tab) => tab !== "review")
+ const next = normalizeAll(all).filter((tab) => tab !== "review")
if (!store.sessionTabs[session]) {
setStore("sessionTabs", session, { all: next, active: undefined })
} else {
@@ -769,7 +841,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
},
async open(tab: string) {
const session = key()
- const next = nextSessionTabsForOpen(store.sessionTabs[session], tab)
+ const next = nextSessionTabsForOpen(store.sessionTabs[session], normalize(tab))
setStore("sessionTabs", session, next)
},
close(tab: string) {