Browse Source

fix(app): project icon color flash on load

Adam 1 month ago
parent
commit
2b9b98e9c2
2 changed files with 55 additions and 14 deletions
  1. 39 8
      packages/app/src/context/global-sync.tsx
  2. 16 6
      packages/app/src/context/layout.tsx

+ 39 - 8
packages/app/src/context/global-sync.tsx

@@ -119,6 +119,22 @@ function createGlobalSync() {
   if (!owner) throw new Error("GlobalSync must be created within owner")
   if (!owner) throw new Error("GlobalSync must be created within owner")
   const vcsCache = new Map<string, VcsCache>()
   const vcsCache = new Map<string, VcsCache>()
   const metaCache = new Map<string, MetaCache>()
   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<{
   const [globalStore, setGlobalStore] = createStore<{
     ready: boolean
     ready: boolean
     error?: InitError
     error?: InitError
@@ -131,7 +147,7 @@ function createGlobalSync() {
   }>({
   }>({
     ready: false,
     ready: false,
     path: { state: "", config: "", worktree: "", directory: "", home: "" },
     path: { state: "", config: "", worktree: "", directory: "", home: "" },
-    project: [],
+    project: projectCache.value,
     provider: { all: [], connected: [], default: {} },
     provider: { all: [], connected: [], default: {} },
     provider_auth: {},
     provider_auth: {},
     config: {},
     config: {},
@@ -139,6 +155,20 @@ function createGlobalSync() {
   })
   })
   let bootstrapQueue: string[] = []
   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 () => {
   createEffect(async () => {
     if (globalStore.reload !== "complete") return
     if (globalStore.reload !== "complete") return
     if (bootstrapQueue.length) {
     if (bootstrapQueue.length) {
@@ -178,7 +208,7 @@ function createGlobalSync() {
       metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] })
       metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] })
 
 
       const init = () => {
       const init = () => {
-        children[directory] = createStore<State>({
+        const child = createStore<State>({
           project: "",
           project: "",
           projectMeta: meta[0].value,
           projectMeta: meta[0].value,
           provider: { all: [], connected: [], default: {} },
           provider: { all: [], connected: [], default: {} },
@@ -201,6 +231,12 @@ function createGlobalSync() {
           message: {},
           message: {},
           part: {},
           part: {},
         })
         })
+
+        children[directory] = child
+
+        createEffect(() => {
+          child[1]("projectMeta", meta[0].value)
+        })
       }
       }
 
 
       runWithOwner(owner, init)
       runWithOwner(owner, init)
@@ -300,12 +336,7 @@ function createGlobalSync() {
         setStore("vcs", (value) => value ?? cached)
         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 = {
       const blockingRequests = {
         project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
         project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),

+ 16 - 6
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.id === projectID)
         : globalSync.data.project.find((x) => x.worktree === project.worktree)
         : 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 = {
       const base = {
         ...(metadata ?? {}),
         ...(metadata ?? {}),
         ...project,
         ...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 {
       return {
         ...base,
         ...base,
+        id: base.id ?? "global",
         name: local?.name,
         name: local?.name,
         commands: local?.commands,
         commands: local?.commands,
         icon: {
         icon: {
@@ -306,10 +314,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
 
 
       for (const project of projects) {
       for (const project of projects) {
         if (project.icon?.color) continue
         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) continue
         if (project.id === "global") {
         if (project.id === "global") {
           globalSync.project.meta(project.worktree, { icon: { color } })
           globalSync.project.meta(project.worktree, { icon: { color } })