authorgravatar for 73941998+UtkarshUsername@users.noreply.github.comUtkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> 2026-07-22 19:50:20+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-22 16:20:20+02:00
log020179c19a0073d130c30083c7623cf1196688e7
tree0cae368c9cd3013a94dee1eeb5e95b8f8c53f72d
parent571a8b44bdd4f0f0b0464ef24240021689616e7d
signature Signed by PGP key B5690EEEBB952194

fix(web): use message-square icon for settled icon-less project threads in sidebar v2 (#4279)


2 files changed, 27 insertions(+), 5 deletions(-)

apps/web/src/components/ProjectFavicon.tsx+25-5
......@@ -1,6 +1,7 @@
11import type { EnvironmentId } from "@t3tools/contracts";
22import { isProjectFaviconFallbackUrl } from "@t3tools/shared/projectFavicon";
33import { FolderIcon } from "lucide-react";
4import type { ComponentType } from "react";
45import { useState } from "react";
56import { useAssetUrl } from "../assets/assetUrls";
67
......@@ -10,29 +11,46 @@ export function ProjectFavicon(input: {
1011 environmentId: EnvironmentId;
1112 cwd: string;
1213 className?: string | undefined;
14 fallbackIcon?: ComponentType<{ className?: string }>;
1315}) {
1416 const src = useAssetUrl(input.environmentId, {
1517 _tag: "project-favicon",
1618 cwd: input.cwd,
1719 });
20 const FallbackIcon = input.fallbackIcon ?? FolderIcon;
1821
1922 if (!src || isProjectFaviconFallbackUrl(src)) {
20 return <ProjectFaviconFallback className={input.className} />;
23 return <ProjectFaviconFallback className={input.className} icon={FallbackIcon} />;
2124 }
2225
23 return <ProjectFaviconImage key={src} src={src} className={input.className} />;
26 return (
27 <ProjectFaviconImage
28 key={src}
29 src={src}
30 className={input.className}
31 fallbackIcon={FallbackIcon}
32 />
33 );
2434}
2535
26function ProjectFaviconFallback({ className }: { readonly className?: string | undefined }) {
27 return <FolderIcon className={`size-3.5 shrink-0 text-muted-foreground/50 ${className ?? ""}`} />;
36function ProjectFaviconFallback({
37 className,
38 icon: Icon,
39}: {
40 readonly className?: string | undefined;
41 readonly icon: ComponentType<{ className?: string }>;
42}) {
43 return <Icon className={`size-3.5 shrink-0 text-muted-foreground/50 ${className ?? ""}`} />;
2844}
2945
3046function ProjectFaviconImage({
3147 src,
3248 className,
49 fallbackIcon: FallbackIcon,
3350}: {
3451 readonly src: string;
3552 readonly className?: string | undefined;
53 readonly fallbackIcon: ComponentType<{ className?: string }>;
3654}) {
3755 const [status, setStatus] = useState<"loading" | "loaded" | "error">(() =>
3856 loadedProjectFaviconSrcs.has(src) ? "loaded" : "loading",
......@@ -40,7 +58,9 @@ function ProjectFaviconImage({
4058
4159 return (
4260 <>
43 {status !== "loaded" ? <ProjectFaviconFallback className={className} /> : null}
61 {status !== "loaded" ? (
62 <ProjectFaviconFallback className={className} icon={FallbackIcon} />
63 ) : null}
4464 <img
4565 src={src}
4666 alt=""
apps/web/src/components/SidebarV2.tsx+2
......@@ -14,6 +14,7 @@ import {
1414 CircleDashedIcon,
1515 CloudIcon,
1616 FolderPlusIcon,
17 MessageSquareIcon,
1718 PlusIcon,
1819 SearchIcon,
1920 SquarePenIcon,
......@@ -426,6 +427,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
426427 environmentId={thread.environmentId}
427428 cwd={props.projectCwd ?? ""}
428429 className="size-3.5"
430 fallbackIcon={MessageSquareIcon}
429431 />
430432 </span>
431433 {title}