CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/components/account/avatar.tsx
Views: 687
1
/*
2
Show an avatar for a given user account.
3
*/
4
5
import { Avatar as AntdAvatar, Popover } from "antd";
6
import { CSSProperties, ReactNode } from "react";
7
import { avatar_fontcolor } from "@cocalc/frontend/account/avatar/font-color";
8
import A from "components/misc/A";
9
import useProfile from "lib/hooks/profile";
10
import useCustomize from "lib/use-customize";
11
12
interface Props {
13
account_id: string;
14
size?: number;
15
style?: CSSProperties;
16
showName?: boolean;
17
extra?: ReactNode; // extra component that gets rendered below avatar when hoving, e.g., could be a "remove" action...
18
zIndex?: number;
19
}
20
21
export default function Avatar({
22
account_id,
23
size,
24
style,
25
showName,
26
extra,
27
zIndex,
28
}: Props) {
29
const { account } = useCustomize();
30
if (size == null) {
31
// Default size=40 to match the cocalc logo.
32
size = 40;
33
}
34
const profile = useProfile({ account_id });
35
36
if (!profile) {
37
// not loaded yet
38
return <DisplayAvatar style={style} size={size} />;
39
}
40
41
return (
42
<Popover
43
mouseLeaveDelay={0.3}
44
zIndex={zIndex}
45
title={
46
<div style={{ textAlign: "center", fontSize: "13pt" }}>
47
{profile.first_name} {profile.last_name}{" "}
48
{profile.name ? `(@${profile.name})` : ""}
49
{account_id == account?.account_id && (
50
<A
51
href="/config/account/name"
52
style={{
53
fontSize: "11px",
54
marginLeft: "10px",
55
float: "right",
56
}}
57
>
58
edit
59
</A>
60
)}
61
</div>
62
}
63
content={
64
<div style={{ textAlign: "center" }}>
65
{profile.image ? (
66
<DisplayAvatar
67
style={style}
68
size={size * 4}
69
image={profile.image}
70
/>
71
) : (
72
<DisplayAvatar
73
style={style}
74
size={size * 4}
75
color={profile.color}
76
letter={profile.first_name?.[0]}
77
/>
78
)}
79
{account_id == account?.account_id && (
80
<div style={{ marginTop: "10px" }}>
81
<A
82
href="/config/account/avatar"
83
style={{
84
fontSize: "11px",
85
}}
86
>
87
edit
88
</A>
89
</div>
90
)}
91
{extra}
92
</div>
93
}
94
>
95
<span style={{ cursor: "pointer" }}>
96
{profile.image ? (
97
<DisplayAvatar style={style} size={size} image={profile.image} />
98
) : (
99
<DisplayAvatar
100
style={style}
101
size={size}
102
color={profile.color}
103
letter={profile.first_name?.[0]}
104
/>
105
)}
106
{showName && (
107
<>
108
<br />
109
{profile.first_name} {profile.last_name}
110
</>
111
)}
112
</span>
113
</Popover>
114
);
115
}
116
117
interface DisplayProps extends Partial<Props> {
118
image?: string;
119
color?: string;
120
letter?: string;
121
}
122
123
export function DisplayAvatar({
124
style,
125
size,
126
image,
127
color,
128
letter,
129
}: DisplayProps) {
130
if (!image && !color && !letter) {
131
return (
132
<AntdAvatar
133
style={{
134
verticalAlign: "middle",
135
...style,
136
}}
137
size={size}
138
></AntdAvatar>
139
);
140
}
141
142
if (image) {
143
return (
144
<AntdAvatar
145
style={{
146
verticalAlign: "middle",
147
...style,
148
}}
149
size={size}
150
src={<img src={image} />}
151
/>
152
);
153
}
154
155
let fontSize: string | undefined = undefined;
156
if (size != null) {
157
if (size >= 32) {
158
fontSize = `${0.75 * size}px`;
159
} else if (size >= 24) {
160
fontSize = "16pt";
161
}
162
}
163
164
if (!color) {
165
// color needs to be something, or below the avatar
166
// will be completely invisible on a black background, e.g.,
167
// in the title bar.
168
color = "#888";
169
}
170
return (
171
<AntdAvatar
172
style={{
173
backgroundColor: color,
174
verticalAlign: "middle",
175
fontSize,
176
color: avatar_fontcolor(color),
177
...style,
178
}}
179
size={size}
180
>
181
{letter ? letter : "?"}
182
</AntdAvatar>
183
);
184
}
185
186