fix: avatar colors

This commit is contained in:
Adam 2025-12-11 15:39:38 -06:00
parent 55957b2ac7
commit e149b7c1e2
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75
4 changed files with 42 additions and 22 deletions

View file

@ -6,18 +6,26 @@ import { useGlobalSync } from "./global-sync"
import { useGlobalSDK } from "./global-sdk"
import { Project } from "@opencode-ai/sdk/v2"
const PASTEL_COLORS = [
"#FCEAFD", // pastel pink
"#FFDFBA", // pastel peach
"#FFFFBA", // pastel yellow
"#BAFFC9", // pastel green
"#EAF6FD", // pastel blue
"#EFEAFD", // pastel lavender
"#FEC8D8", // pastel rose
"#D4F0F0", // pastel cyan
"#FDF0EA", // pastel coral
"#C1E1C1", // pastel mint
]
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
export type AvatarColorKey = (typeof AVATAR_COLOR_KEYS)[number]
export function isAvatarColorKey(value: string): value is AvatarColorKey {
return AVATAR_COLOR_KEYS.includes(value as AvatarColorKey)
}
export function getAvatarColors(key?: string) {
if (key && isAvatarColorKey(key)) {
return {
background: `var(--avatar-background-${key})`,
foreground: `var(--avatar-text-${key})`,
}
}
return {
background: "var(--surface-info-base)",
foreground: "var(--text-base)",
}
}
type Dialog = "provider" | "model" | "connect"
@ -58,11 +66,11 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
connect: {},
dialog: {},
})
const usedColors = new Set<string>()
const usedColors = new Set<AvatarColorKey>()
function pickAvailableColor() {
const available = PASTEL_COLORS.filter((c) => !usedColors.has(c))
if (available.length === 0) return PASTEL_COLORS[Math.floor(Math.random() * PASTEL_COLORS.length)]
function pickAvailableColor(): AvatarColorKey {
const available = AVATAR_COLOR_KEYS.filter((c) => !usedColors.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)]
}

View file

@ -1,7 +1,7 @@
import { createEffect, createMemo, For, Match, onCleanup, onMount, ParentProps, Show, Switch, type JSX } from "solid-js"
import { DateTime } from "luxon"
import { A, useNavigate, useParams } from "@solidjs/router"
import { useLayout } from "@/context/layout"
import { useLayout, getAvatarColors } from "@/context/layout"
import { useGlobalSync } from "@/context/global-sync"
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
import { Mark } from "@opencode-ai/ui/logo"
@ -180,7 +180,7 @@ export default function Layout(props: ParentProps) {
<Avatar
fallback={name()}
src={props.project.icon?.url}
background={props.project.icon?.color ?? "var(--surface-info-base)"}
{...getAvatarColors(props.project.icon?.color)}
class="size-full"
/>
</div>
@ -200,7 +200,7 @@ export default function Layout(props: ParentProps) {
<Avatar
fallback={name()}
src={props.project.icon?.url}
background={props.project.icon?.color ?? "var(--surface-info-base)"}
{...getAvatarColors(props.project.icon?.color)}
class="size-full"
/>
</div>
@ -231,7 +231,7 @@ export default function Layout(props: ParentProps) {
<Avatar
fallback={name()}
src={props.project.icon?.url}
background={props.project.icon?.color ?? "var(--surface-info-base)"}
{...getAvatarColors(props.project.icon?.color)}
class="size-full group-hover/session:hidden"
/>
<Icon

View file

@ -1,5 +1,6 @@
[data-component="avatar"] {
--avatar-bg: var(--color-surface-info-base);
--avatar-fg: var(--color-text-base);
display: flex;
align-items: center;
justify-content: center;
@ -10,7 +11,7 @@
font-weight: 500;
text-transform: uppercase;
background-color: var(--avatar-bg);
color: oklch(from var(--avatar-bg) calc(l * 0.72) calc(c * 8) h);
color: var(--avatar-fg);
}
[data-component="avatar"][data-has-image] {

View file

@ -4,11 +4,21 @@ export interface AvatarProps extends ComponentProps<"div"> {
fallback: string
src?: string
background?: string
foreground?: string
size?: "small" | "normal" | "large"
}
export function Avatar(props: AvatarProps) {
const [split, rest] = splitProps(props, ["fallback", "src", "background", "size", "class", "classList", "style"])
const [split, rest] = splitProps(props, [
"fallback",
"src",
"background",
"foreground",
"size",
"class",
"classList",
"style",
])
const src = split.src // did this so i can zero it out to test fallback
return (
<div
@ -23,6 +33,7 @@ export function Avatar(props: AvatarProps) {
style={{
...(typeof split.style === "object" ? split.style : {}),
...(!src && split.background ? { "--avatar-bg": split.background } : {}),
...(!src && split.foreground ? { "--avatar-fg": split.foreground } : {}),
}}
>
<Show when={src} fallback={split.fallback?.[0]}>