summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-19 14:59:41 -0600
committerAdam <[email protected]>2026-01-19 14:59:47 -0600
commita4d1824412c57d733c33c58e19551f0818c82e8a (patch)
tree8530a4594b6d760ad03f775ecc96dd8324b9c410 /packages/app/src
parentcac35bc52d9a8a2c9ca673510b2266d1c13ee141 (diff)
downloadopencode-a4d1824412c57d733c33c58e19551f0818c82e8a.tar.gz
opencode-a4d1824412c57d733c33c58e19551f0818c82e8a.zip
fix(app): no more favicons
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/components/dialog-edit-project.tsx4
-rw-r--r--packages/app/src/context/layout.tsx62
-rw-r--r--packages/app/src/pages/layout.tsx2
3 files changed, 44 insertions, 24 deletions
diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx
index 091f00702..7acb766f8 100644
--- a/packages/app/src/components/dialog-edit-project.tsx
+++ b/packages/app/src/components/dialog-edit-project.tsx
@@ -22,7 +22,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
const [store, setStore] = createStore({
name: defaultName(),
color: props.project.icon?.color || "pink",
- iconUrl: props.project.icon?.url || "",
+ iconUrl: props.project.icon?.override || "",
saving: false,
})
@@ -74,7 +74,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
await globalSDK.client.project.update({
projectID: props.project.id,
name,
- icon: { color: store.color, url: store.iconUrl },
+ icon: { color: store.color, override: store.iconUrl },
})
setStore("saving", false)
dialog.close()
diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx
index a8a8ce1e9..d7d09aa39 100644
--- a/packages/app/src/context/layout.tsx
+++ b/packages/app/src/context/layout.tsx
@@ -208,10 +208,10 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
})
})
- const usedColors = new Set<AvatarColorKey>()
+ const [colors, setColors] = createStore<Record<string, AvatarColorKey>>({})
- function pickAvailableColor(): AvatarColorKey {
- const available = AVATAR_COLOR_KEYS.filter((c) => !usedColors.has(c))
+ function pickAvailableColor(used: Set<string>): AvatarColorKey {
+ const available = AVATAR_COLOR_KEYS.filter((c) => !used.has(c))
if (available.length === 0) return AVATAR_COLOR_KEYS[Math.floor(Math.random() * AVATAR_COLOR_KEYS.length)]
return available[Math.floor(Math.random() * available.length)]
}
@@ -222,24 +222,15 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
const metadata = projectID
? globalSync.data.project.find((x) => x.id === projectID)
: globalSync.data.project.find((x) => x.worktree === project.worktree)
- return [
- {
- ...(metadata ?? {}),
- ...project,
- icon: { url: metadata?.icon?.url, color: metadata?.icon?.color },
+ return {
+ ...(metadata ?? {}),
+ ...project,
+ icon: {
+ url: metadata?.icon?.url,
+ override: metadata?.icon?.override,
+ color: metadata?.icon?.color,
},
- ]
- }
-
- function colorize(project: LocalProject) {
- if (project.icon?.color) return project
- const color = pickAvailableColor()
- usedColors.add(color)
- project.icon = { ...project.icon, color }
- if (project.id) {
- globalSdk.client.project.update({ projectID: project.id, icon: { color } })
}
- return project
}
const roots = createMemo(() => {
@@ -277,8 +268,37 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
})
})
- const enriched = createMemo(() => server.projects.list().flatMap(enrich))
- const list = createMemo(() => enriched().flatMap(colorize))
+ const enriched = createMemo(() => server.projects.list().map(enrich))
+ const list = createMemo(() => {
+ const projects = enriched()
+ return projects.map((project) => {
+ const color = project.icon?.color ?? colors[project.worktree]
+ if (!color) return project
+ const icon = project.icon ? { ...project.icon, color } : { color }
+ return { ...project, icon }
+ })
+ })
+
+ createEffect(() => {
+ const projects = enriched()
+ if (projects.length === 0) return
+
+ const used = new Set<string>()
+ for (const project of projects) {
+ const color = project.icon?.color ?? colors[project.worktree]
+ if (color) used.add(color)
+ }
+
+ 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)
+ if (!project.id) continue
+ void globalSdk.client.project.update({ projectID: project.id, icon: { color } })
+ }
+ })
onMount(() => {
Promise.all(
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
index a8f9b162f..9daac949e 100644
--- a/packages/app/src/pages/layout.tsx
+++ b/packages/app/src/pages/layout.tsx
@@ -1284,7 +1284,7 @@ export default function Layout(props: ParentProps) {
<div class="size-full rounded overflow-clip">
<Avatar
fallback={name()}
- src={props.project.id === opencode ? "https://opencode.ai/favicon-v2.svg" : props.project.icon?.url}
+ src={props.project.id === opencode ? "https://opencode.ai/favicon-v2.svg" : props.project.icon?.override}
{...getAvatarColors(props.project.icon?.color)}
class="size-full rounded"
style={