summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-22 19:54:53 -0600
committerAdam <[email protected]>2026-01-22 20:17:50 -0600
commit2b9b98e9c2bee444f5110073203be55c6b49e73d (patch)
tree35861bdcf9ad16fcb975d4e2c0e3497c0bb588d7 /packages/app/src
parent07015aae074bccf31af42b2cae1701e9d4c32451 (diff)
downloadopencode-2b9b98e9c2bee444f5110073203be55c6b49e73d.tar.gz
opencode-2b9b98e9c2bee444f5110073203be55c6b49e73d.zip
fix(app): project icon color flash on load
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/context/global-sync.tsx47
-rw-r--r--packages/app/src/context/layout.tsx22
2 files changed, 55 insertions, 14 deletions
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
index ec072e7be..b6d9b518f 100644
--- a/packages/app/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -119,6 +119,22 @@ function createGlobalSync() {
if (!owner) throw new Error("GlobalSync must be created within owner")
const vcsCache = new Map<string, VcsCache>()
const metaCache = new Map<string, MetaCache>()
+
+ const [projectCache, setProjectCache, , projectCacheReady] = persisted(
+ Persist.global("globalSync.project", ["globalSync.project.v1"]),
+ createStore({ value: [] as Project[] }),
+ )
+
+ const sanitizeProject = (project: Project) => {
+ if (!project.icon?.url) return project
+ return {
+ ...project,
+ icon: {
+ ...project.icon,
+ url: undefined,
+ },
+ }
+ }
const [globalStore, setGlobalStore] = createStore<{
ready: boolean
error?: InitError
@@ -131,7 +147,7 @@ function createGlobalSync() {
}>({
ready: false,
path: { state: "", config: "", worktree: "", directory: "", home: "" },
- project: [],
+ project: projectCache.value,
provider: { all: [], connected: [], default: {} },
provider_auth: {},
config: {},
@@ -139,6 +155,20 @@ function createGlobalSync() {
})
let bootstrapQueue: string[] = []
+ createEffect(() => {
+ if (!projectCacheReady()) return
+ if (globalStore.project.length !== 0) return
+ const cached = projectCache.value
+ if (cached.length === 0) return
+ setGlobalStore("project", cached)
+ })
+
+ createEffect(() => {
+ if (!projectCacheReady()) return
+ if (globalStore.project.length === 0 && projectCache.value.length !== 0) return
+ setProjectCache("value", globalStore.project.map(sanitizeProject))
+ })
+
createEffect(async () => {
if (globalStore.reload !== "complete") return
if (bootstrapQueue.length) {
@@ -178,7 +208,7 @@ function createGlobalSync() {
metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] })
const init = () => {
- children[directory] = createStore<State>({
+ const child = createStore<State>({
project: "",
projectMeta: meta[0].value,
provider: { all: [], connected: [], default: {} },
@@ -201,6 +231,12 @@ function createGlobalSync() {
message: {},
part: {},
})
+
+ children[directory] = child
+
+ createEffect(() => {
+ child[1]("projectMeta", meta[0].value)
+ })
}
runWithOwner(owner, init)
@@ -300,12 +336,7 @@ function createGlobalSync() {
setStore("vcs", (value) => value ?? cached)
})
- createEffect(() => {
- if (!meta.ready()) return
- const cached = meta.store.value
- if (!cached) return
- setStore("projectMeta", (value) => value ?? cached)
- })
+ // projectMeta is synced from persisted storage in ensureChild.
const blockingRequests = {
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx
index 3c544b069..9db03b25f 100644
--- a/packages/app/src/context/layout.tsx
+++ b/packages/app/src/context/layout.tsx
@@ -223,6 +223,13 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
? globalSync.data.project.find((x) => x.id === projectID)
: globalSync.data.project.find((x) => x.worktree === project.worktree)
+ const local = childStore.projectMeta
+ const localOverride =
+ local?.name !== undefined ||
+ local?.commands?.start !== undefined ||
+ local?.icon?.override !== undefined ||
+ local?.icon?.color !== undefined
+
const base = {
...(metadata ?? {}),
...project,
@@ -233,11 +240,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
},
}
- if (projectID !== "global") return base
+ const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
+ if (!isGlobal) return base
- const local = childStore.projectMeta
return {
...base,
+ id: base.id ?? "global",
name: local?.name,
commands: local?.commands,
icon: {
@@ -306,10 +314,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
for (const project of projects) {
if (project.icon?.color) continue
- if (colors[project.worktree]) continue
- const color = pickAvailableColor(used)
- used.add(color)
- setColors(project.worktree, color)
+ const existing = colors[project.worktree]
+ const color = existing ?? pickAvailableColor(used)
+ if (!existing) {
+ used.add(color)
+ setColors(project.worktree, color)
+ }
if (!project.id) continue
if (project.id === "global") {
globalSync.project.meta(project.worktree, { icon: { color } })