Skip to content

Commit 2b9b98e

Browse files
committed
fix(app): project icon color flash on load
1 parent 07015aa commit 2b9b98e

2 files changed

Lines changed: 55 additions & 14 deletions

File tree

packages/app/src/context/global-sync.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,22 @@ function createGlobalSync() {
119119
if (!owner) throw new Error("GlobalSync must be created within owner")
120120
const vcsCache = new Map<string, VcsCache>()
121121
const metaCache = new Map<string, MetaCache>()
122+
123+
const [projectCache, setProjectCache, , projectCacheReady] = persisted(
124+
Persist.global("globalSync.project", ["globalSync.project.v1"]),
125+
createStore({ value: [] as Project[] }),
126+
)
127+
128+
const sanitizeProject = (project: Project) => {
129+
if (!project.icon?.url) return project
130+
return {
131+
...project,
132+
icon: {
133+
...project.icon,
134+
url: undefined,
135+
},
136+
}
137+
}
122138
const [globalStore, setGlobalStore] = createStore<{
123139
ready: boolean
124140
error?: InitError
@@ -131,14 +147,28 @@ function createGlobalSync() {
131147
}>({
132148
ready: false,
133149
path: { state: "", config: "", worktree: "", directory: "", home: "" },
134-
project: [],
150+
project: projectCache.value,
135151
provider: { all: [], connected: [], default: {} },
136152
provider_auth: {},
137153
config: {},
138154
reload: undefined,
139155
})
140156
let bootstrapQueue: string[] = []
141157

158+
createEffect(() => {
159+
if (!projectCacheReady()) return
160+
if (globalStore.project.length !== 0) return
161+
const cached = projectCache.value
162+
if (cached.length === 0) return
163+
setGlobalStore("project", cached)
164+
})
165+
166+
createEffect(() => {
167+
if (!projectCacheReady()) return
168+
if (globalStore.project.length === 0 && projectCache.value.length !== 0) return
169+
setProjectCache("value", globalStore.project.map(sanitizeProject))
170+
})
171+
142172
createEffect(async () => {
143173
if (globalStore.reload !== "complete") return
144174
if (bootstrapQueue.length) {
@@ -178,7 +208,7 @@ function createGlobalSync() {
178208
metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] })
179209

180210
const init = () => {
181-
children[directory] = createStore<State>({
211+
const child = createStore<State>({
182212
project: "",
183213
projectMeta: meta[0].value,
184214
provider: { all: [], connected: [], default: {} },
@@ -201,6 +231,12 @@ function createGlobalSync() {
201231
message: {},
202232
part: {},
203233
})
234+
235+
children[directory] = child
236+
237+
createEffect(() => {
238+
child[1]("projectMeta", meta[0].value)
239+
})
204240
}
205241

206242
runWithOwner(owner, init)
@@ -300,12 +336,7 @@ function createGlobalSync() {
300336
setStore("vcs", (value) => value ?? cached)
301337
})
302338

303-
createEffect(() => {
304-
if (!meta.ready()) return
305-
const cached = meta.store.value
306-
if (!cached) return
307-
setStore("projectMeta", (value) => value ?? cached)
308-
})
339+
// projectMeta is synced from persisted storage in ensureChild.
309340

310341
const blockingRequests = {
311342
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),

packages/app/src/context/layout.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
223223
? globalSync.data.project.find((x) => x.id === projectID)
224224
: globalSync.data.project.find((x) => x.worktree === project.worktree)
225225

226+
const local = childStore.projectMeta
227+
const localOverride =
228+
local?.name !== undefined ||
229+
local?.commands?.start !== undefined ||
230+
local?.icon?.override !== undefined ||
231+
local?.icon?.color !== undefined
232+
226233
const base = {
227234
...(metadata ?? {}),
228235
...project,
@@ -233,11 +240,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
233240
},
234241
}
235242

236-
if (projectID !== "global") return base
243+
const isGlobal = projectID === "global" || (metadata?.id === undefined && localOverride)
244+
if (!isGlobal) return base
237245

238-
const local = childStore.projectMeta
239246
return {
240247
...base,
248+
id: base.id ?? "global",
241249
name: local?.name,
242250
commands: local?.commands,
243251
icon: {
@@ -306,10 +314,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
306314

307315
for (const project of projects) {
308316
if (project.icon?.color) continue
309-
if (colors[project.worktree]) continue
310-
const color = pickAvailableColor(used)
311-
used.add(color)
312-
setColors(project.worktree, color)
317+
const existing = colors[project.worktree]
318+
const color = existing ?? pickAvailableColor(used)
319+
if (!existing) {
320+
used.add(color)
321+
setColors(project.worktree, color)
322+
}
313323
if (!project.id) continue
314324
if (project.id === "global") {
315325
globalSync.project.meta(project.worktree, { icon: { color } })

0 commit comments

Comments
 (0)