@@ -12,6 +12,7 @@ import { type LocalProject, getAvatarColors } from "@/context/layout"
1212import { getFilename } from "@opencode-ai/shared/util/path"
1313import { Avatar } from "@opencode-ai/ui/avatar"
1414import { useLanguage } from "@/context/language"
15+ import { getProjectAvatarSource } from "@/pages/layout/sidebar-items"
1516
1617const AVATAR_COLOR_KEYS = [ "pink" , "mint" , "orange" , "purple" , "cyan" , "lime" ] as const
1718
@@ -26,8 +27,8 @@ export function DialogEditProject(props: { project: LocalProject }) {
2627
2728 const [ store , setStore ] = createStore ( {
2829 name : defaultName ( ) ,
29- color : props . project . icon ?. color || "pink" ,
30- iconUrl : props . project . icon ?. override || "" ,
30+ color : props . project . icon ?. color ,
31+ iconOverride : props . project . icon ?. override ,
3132 startup : props . project . commands ?. start ?? "" ,
3233 dragOver : false ,
3334 iconHover : false ,
@@ -39,7 +40,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
3940 if ( ! file . type . startsWith ( "image/" ) ) return
4041 const reader = new FileReader ( )
4142 reader . onload = ( e ) => {
42- setStore ( "iconUrl " , e . target ?. result as string )
43+ setStore ( "iconOverride " , e . target ?. result as string )
4344 setStore ( "iconHover" , false )
4445 }
4546 reader . readAsDataURL ( file )
@@ -68,7 +69,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
6869 }
6970
7071 function clearIcon ( ) {
71- setStore ( "iconUrl " , "" )
72+ setStore ( "iconOverride " , "" )
7273 }
7374
7475 const saveMutation = useMutation ( ( ) => ( {
@@ -81,17 +82,17 @@ export function DialogEditProject(props: { project: LocalProject }) {
8182 projectID : props . project . id ,
8283 directory : props . project . worktree ,
8384 name,
84- icon : { color : store . color , override : store . iconUrl } ,
85+ icon : { color : store . color || "" , override : store . iconOverride || "" } ,
8586 commands : { start } ,
8687 } )
87- globalSync . project . icon ( props . project . worktree , store . iconUrl || undefined )
88+ globalSync . project . icon ( props . project . worktree , store . iconOverride || undefined )
8889 dialog . close ( )
8990 return
9091 }
9192
9293 globalSync . project . meta ( props . project . worktree , {
9394 name,
94- icon : { color : store . color , override : store . iconUrl || undefined } ,
95+ icon : { color : store . color || undefined , override : store . iconOverride || undefined } ,
9596 commands : { start : start || undefined } ,
9697 } )
9798 dialog . close ( )
@@ -130,21 +131,25 @@ export function DialogEditProject(props: { project: LocalProject }) {
130131 classList = { {
131132 "border-text-interactive-base bg-surface-info-base/20" : store . dragOver ,
132133 "border-border-base hover:border-border-strong" : ! store . dragOver ,
133- "overflow-hidden" : ! ! store . iconUrl ,
134+ "overflow-hidden" : ! ! store . iconOverride ,
134135 } }
135136 onDrop = { handleDrop }
136137 onDragOver = { handleDragOver }
137138 onDragLeave = { handleDragLeave }
138139 onClick = { ( ) => {
139- if ( store . iconUrl && store . iconHover ) {
140+ if ( store . iconOverride && store . iconHover ) {
140141 clearIcon ( )
141142 } else {
142143 iconInput ?. click ( )
143144 }
144145 } }
145146 >
146147 < Show
147- when = { store . iconUrl }
148+ when = { getProjectAvatarSource ( props . project . id , {
149+ color : store . color ,
150+ url : props . project . icon ?. url ,
151+ override : store . iconOverride ,
152+ } ) }
148153 fallback = {
149154 < div class = "size-full flex items-center justify-center" >
150155 < Avatar
@@ -155,27 +160,29 @@ export function DialogEditProject(props: { project: LocalProject }) {
155160 </ div >
156161 }
157162 >
158- < img
159- src = { store . iconUrl }
160- alt = { language . t ( "dialog.project.edit.icon.alt" ) }
161- class = "size-full object-cover"
162- />
163+ { ( src ) => (
164+ < img
165+ src = { src ( ) }
166+ alt = { language . t ( "dialog.project.edit.icon.alt" ) }
167+ class = "size-full object-cover"
168+ />
169+ ) }
163170 </ Show >
164171 </ div >
165172 < div
166173 class = "absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
167174 classList = { {
168- "opacity-100" : store . iconHover && ! store . iconUrl ,
169- "opacity-0" : ! ( store . iconHover && ! store . iconUrl ) ,
175+ "opacity-100" : store . iconHover && ! store . iconOverride ,
176+ "opacity-0" : ! ( store . iconHover && ! store . iconOverride ) ,
170177 } }
171178 >
172179 < Icon name = "cloud-upload" size = "large" class = "text-icon-on-interactive-base drop-shadow-sm" />
173180 </ div >
174181 < div
175182 class = "absolute inset-0 size-16 bg-surface-raised-stronger-non-alpha/90 rounded-[6px] z-10 pointer-events-none flex items-center justify-center transition-opacity"
176183 classList = { {
177- "opacity-100" : store . iconHover && ! ! store . iconUrl ,
178- "opacity-0" : ! ( store . iconHover && ! ! store . iconUrl ) ,
184+ "opacity-100" : store . iconHover && ! ! store . iconOverride ,
185+ "opacity-0" : ! ( store . iconHover && ! ! store . iconOverride ) ,
179186 } }
180187 >
181188 < Icon name = "trash" size = "large" class = "text-icon-on-interactive-base drop-shadow-sm" />
@@ -198,7 +205,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
198205 </ div >
199206 </ div >
200207
201- < Show when = { ! store . iconUrl } >
208+ < Show when = { ! store . iconOverride } >
202209 < div class = "flex flex-col gap-2" >
203210 < label class = "text-12-medium text-text-weak" > { language . t ( "dialog.project.edit.color" ) } </ label >
204211 < div class = "flex gap-1.5" >
@@ -215,7 +222,10 @@ export function DialogEditProject(props: { project: LocalProject }) {
215222 "bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base" :
216223 store . color !== color ,
217224 } }
218- onClick = { ( ) => setStore ( "color" , color ) }
225+ onClick = { ( ) => {
226+ if ( store . color === color && ! props . project . icon ?. url ) return
227+ setStore ( "color" , store . color === color ? undefined : color )
228+ } }
219229 >
220230 < Avatar
221231 fallback = { store . name || defaultName ( ) }
0 commit comments