Skip to content

Commit e0a8b59

Browse files
committed
Allows you to add your company url to generate a logo from the settings page
1 parent a869d76 commit e0a8b59

File tree

5 files changed

+305
-113
lines changed

5 files changed

+305
-113
lines changed

apps/webapp/app/components/primitives/Avatar.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import {
2+
BoltIcon,
23
BuildingOffice2Icon,
34
CodeBracketSquareIcon,
45
FaceSmileIcon,
56
FireIcon,
7+
GlobeAltIcon,
68
RocketLaunchIcon,
79
StarIcon,
810
} from "@heroicons/react/20/solid";
@@ -25,7 +27,8 @@ export const AvatarData = z.discriminatedUnion("type", [
2527
}),
2628
z.object({
2729
type: z.literal(AvatarType.enum.image),
28-
url: z.string().url(),
30+
url: z.string(),
31+
lastIconHex: z.string().optional(),
2932
}),
3033
]);
3134

@@ -85,6 +88,7 @@ export const avatarIcons: Record<string, React.ComponentType<React.SVGProps<SVGS
8588
"hero:fire": FireIcon,
8689
"hero:star": StarIcon,
8790
"hero:face-smile": FaceSmileIcon,
91+
"hero:bolt": BoltIcon,
8892
};
8993

9094
export const defaultAvatarColors = [
@@ -179,9 +183,21 @@ function AvatarIcon({
179183
}
180184

181185
function AvatarImage({ avatar, size }: { avatar: ImageAvatar; size: number }) {
186+
if (!avatar.url) {
187+
return (
188+
<span className="grid shrink-0 place-items-center" style={styleFromSize(size)}>
189+
<GlobeAltIcon className="size-[90%] text-text-dimmed" />
190+
</span>
191+
);
192+
}
193+
182194
return (
183-
<span className="grid place-items-center" style={styleFromSize(size)}>
184-
<img src={avatar.url} alt="Organization avatar" className="size-6" />
195+
<span className="grid shrink-0 place-items-center" style={styleFromSize(size)}>
196+
<img
197+
src={avatar.url}
198+
alt="Organization avatar"
199+
className="size-full rounded-[10%] object-contain"
200+
/>
185201
</span>
186202
);
187203
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useCallback, useEffect, useRef, useState } from "react";
2+
import { extractDomain, faviconUrl } from "~/utils/favicon";
3+
4+
export function useFaviconUrl(urlInput: string, size: number = 64) {
5+
const [url, setUrl] = useState<string | null>(null);
6+
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
7+
8+
const update = useCallback(
9+
(value: string) => {
10+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
11+
timeoutRef.current = setTimeout(() => {
12+
const domain = extractDomain(value);
13+
if (domain && domain.includes(".")) {
14+
setUrl(faviconUrl(domain, size));
15+
} else {
16+
setUrl(null);
17+
}
18+
}, 400);
19+
},
20+
[size]
21+
);
22+
23+
useEffect(() => {
24+
update(urlInput);
25+
return () => {
26+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
27+
};
28+
}, [urlInput, update]);
29+
30+
return url;
31+
}

0 commit comments

Comments
 (0)