Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/mobile/src/components/ProjectFavicon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
projectAutoMonogram,
projectIconColorClassNames,
resolveProjectIconGlyph,
resolveProjectIconSymbol,
type ProjectIconGlyph,
} from "../lib/projectIcon";

Expand All @@ -40,6 +41,7 @@ export const ProjectFavicon = memo(function ProjectFavicon(props: {
readonly projectIcon?: ProjectIconOverride | null;
}) {
const size = props.size ?? 42;
const symbol = resolveProjectIconSymbol(props.projectIcon);
const glyph = resolveProjectIconGlyph(props.projectIcon, props.projectTitle);
const faviconUrl = useAtomValue(
props.workspaceRoot == null || glyph !== null
Expand Down Expand Up @@ -74,6 +76,17 @@ export const ProjectFavicon = memo(function ProjectFavicon(props: {
[renderableFaviconUrl, props.environmentId, props.workspaceRoot, props.faviconPath],
);

if (symbol !== null) {
return (
<SymbolView
name={symbol.name}
size={size}
tintColorClassName={projectIconColorClassNames(symbol.color).tint}
type="monochrome"
/>
);
}

if (glyph !== null) {
return <ProjectIconGlyphView glyph={glyph} size={size} />;
}
Expand Down
59 changes: 40 additions & 19 deletions apps/mobile/src/lib/projectIcon.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isScratchProject } from "@t3tools/client-runtime/state/projects";
import { ProjectIconColor, type ProjectIconOverride } from "@t3tools/contracts";
import { isProjectFaviconFallbackUrl } from "@t3tools/shared/projectFavicon";
import type { AppSymbolName } from "../components/ui/AppSymbol";

export type ProjectIconGlyph =
| { readonly kind: "emoji"; readonly emoji: string }
Expand Down Expand Up @@ -66,6 +67,18 @@ export function resolveProjectIconGlyph(
}
}

const SYMBOL_BY_LUCIDE_NAME: Partial<Record<string, AppSymbolName>> = {
"message-square-dashed": "text.bubble",
};

export function resolveProjectIconSymbol(
projectIcon: ProjectIconOverride | null | undefined,
): { readonly name: AppSymbolName; readonly color: ProjectIconColor } | null {
if (projectIcon?.kind !== "lucide") return null;
const name = SYMBOL_BY_LUCIDE_NAME[projectIcon.name];
return name ? { name, color: projectIcon.color } : null;
}

export type ProjectChipIcon = { readonly kind: "favicon"; readonly uri: string } | ProjectIconGlyph;

export function resolveProjectChipIcon(
Expand All @@ -87,26 +100,34 @@ export function resolveProjectChipIcon(

const PROJECT_ICON_COLOR_CLASSES: Record<
ProjectIconColor,
{ readonly text: string; readonly background: string }
{ readonly text: string; readonly tint: string; readonly background: string }
> = {
gray: { text: "text-gray-500", background: "bg-gray-500/15" },
red: { text: "text-red-500", background: "bg-red-500/15" },
orange: { text: "text-orange-500", background: "bg-orange-500/15" },
amber: { text: "text-amber-500", background: "bg-amber-500/15" },
yellow: { text: "text-yellow-500", background: "bg-yellow-500/15" },
lime: { text: "text-lime-500", background: "bg-lime-500/15" },
green: { text: "text-green-500", background: "bg-green-500/15" },
emerald: { text: "text-emerald-500", background: "bg-emerald-500/15" },
teal: { text: "text-teal-500", background: "bg-teal-500/15" },
cyan: { text: "text-cyan-500", background: "bg-cyan-500/15" },
sky: { text: "text-sky-500", background: "bg-sky-500/15" },
blue: { text: "text-blue-500", background: "bg-blue-500/15" },
indigo: { text: "text-indigo-500", background: "bg-indigo-500/15" },
violet: { text: "text-violet-500", background: "bg-violet-500/15" },
purple: { text: "text-purple-500", background: "bg-purple-500/15" },
fuchsia: { text: "text-fuchsia-500", background: "bg-fuchsia-500/15" },
pink: { text: "text-pink-500", background: "bg-pink-500/15" },
rose: { text: "text-rose-500", background: "bg-rose-500/15" },
gray: { text: "text-gray-500", tint: "accent-gray-500", background: "bg-gray-500/15" },
red: { text: "text-red-500", tint: "accent-red-500", background: "bg-red-500/15" },
orange: { text: "text-orange-500", tint: "accent-orange-500", background: "bg-orange-500/15" },
amber: { text: "text-amber-500", tint: "accent-amber-500", background: "bg-amber-500/15" },
yellow: { text: "text-yellow-500", tint: "accent-yellow-500", background: "bg-yellow-500/15" },
lime: { text: "text-lime-500", tint: "accent-lime-500", background: "bg-lime-500/15" },
green: { text: "text-green-500", tint: "accent-green-500", background: "bg-green-500/15" },
emerald: {
text: "text-emerald-500",
tint: "accent-emerald-500",
background: "bg-emerald-500/15",
},
teal: { text: "text-teal-500", tint: "accent-teal-500", background: "bg-teal-500/15" },
cyan: { text: "text-cyan-500", tint: "accent-cyan-500", background: "bg-cyan-500/15" },
sky: { text: "text-sky-500", tint: "accent-sky-500", background: "bg-sky-500/15" },
blue: { text: "text-blue-500", tint: "accent-blue-500", background: "bg-blue-500/15" },
indigo: { text: "text-indigo-500", tint: "accent-indigo-500", background: "bg-indigo-500/15" },
violet: { text: "text-violet-500", tint: "accent-violet-500", background: "bg-violet-500/15" },
purple: { text: "text-purple-500", tint: "accent-purple-500", background: "bg-purple-500/15" },
fuchsia: {
text: "text-fuchsia-500",
tint: "accent-fuchsia-500",
background: "bg-fuchsia-500/15",
},
pink: { text: "text-pink-500", tint: "accent-pink-500", background: "bg-pink-500/15" },
rose: { text: "text-rose-500", tint: "accent-rose-500", background: "bg-rose-500/15" },
};

export function projectIconColorClassNames(color: ProjectIconColor) {
Expand Down
Loading