Skip to content

Commit 3a4e685

Browse files
Hybrid SSO icons: inline SVGs for top providers, Simple Icons CDN fallback
Keep multicolor inline SVGs for Google, GitHub, GitLab, Microsoft, Facebook, and Apple. Fall back to Simple Icons CDN for any other provider, with a letter avatar as the final fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 0c8c226 commit 3a4e685

2 files changed

Lines changed: 117 additions & 9 deletions

File tree

packages/managed-auth-react/src/components/icons.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,85 @@ export const SpinnerIcon = (p: IconProps) => (
198198
/>
199199
</svg>
200200
);
201+
202+
// SSO provider marks
203+
export const GoogleMark = (p: IconProps) => (
204+
<svg viewBox="0 0 24 24" aria-hidden="true" {...p}>
205+
<path
206+
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
207+
fill="#4285F4"
208+
/>
209+
<path
210+
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
211+
fill="#34A853"
212+
/>
213+
<path
214+
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
215+
fill="#FBBC05"
216+
/>
217+
<path
218+
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
219+
fill="#EA4335"
220+
/>
221+
</svg>
222+
);
223+
224+
export const GitHubMark = (p: IconProps) => (
225+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" {...p}>
226+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
227+
</svg>
228+
);
229+
230+
export const GitLabMark = (p: IconProps) => (
231+
<svg viewBox="0 0 24 24" aria-hidden="true" {...p}>
232+
<path d="M12 23.054l3.684-11.335H8.316L12 23.054z" fill="#E24329" />
233+
<path
234+
d="M12 23.054L8.316 11.719H1.647L12 23.054z"
235+
fill="#FC6D26"
236+
/>
237+
<path
238+
d="M1.647 11.719L.253 16.01a.95.95 0 00.346 1.062L12 23.054 1.647 11.719z"
239+
fill="#FCA326"
240+
/>
241+
<path
242+
d="M1.647 11.719h6.669L5.633.926a.477.477 0 00-.908 0L1.647 11.719z"
243+
fill="#E24329"
244+
/>
245+
<path
246+
d="M12 23.054l3.684-11.335h6.669L12 23.054z"
247+
fill="#FC6D26"
248+
/>
249+
<path
250+
d="M22.353 11.719l1.394 4.291a.95.95 0 01-.346 1.062L12 23.054l10.353-11.335z"
251+
fill="#FCA326"
252+
/>
253+
<path
254+
d="M22.353 11.719h-6.669l2.683-10.793a.477.477 0 01.908 0l3.078 10.793z"
255+
fill="#E24329"
256+
/>
257+
</svg>
258+
);
259+
260+
export const MicrosoftMark = (p: IconProps) => (
261+
<svg viewBox="0 0 24 24" aria-hidden="true" {...p}>
262+
<path d="M1 1h10.5v10.5H1V1z" fill="#F25022" />
263+
<path d="M12.5 1H23v10.5H12.5V1z" fill="#7FBA00" />
264+
<path d="M1 12.5h10.5V23H1V12.5z" fill="#00A4EF" />
265+
<path d="M12.5 12.5H23V23H12.5V12.5z" fill="#FFB900" />
266+
</svg>
267+
);
268+
269+
export const FacebookMark = (p: IconProps) => (
270+
<svg viewBox="0 0 24 24" aria-hidden="true" {...p}>
271+
<path
272+
d="M24 12c0-6.627-5.373-12-12-12S0 5.373 0 12c0 5.99 4.388 10.954 10.125 11.854V15.47H7.078V12h3.047V9.356c0-3.007 1.792-4.668 4.533-4.668 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874V12h3.328l-.532 3.47h-2.796v8.384C19.612 22.954 24 17.99 24 12z"
273+
fill="#1877F2"
274+
/>
275+
</svg>
276+
);
277+
278+
export const AppleMark = (p: IconProps) => (
279+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" {...p}>
280+
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" />
281+
</svg>
282+
);

packages/managed-auth-react/src/components/sso-provider.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
11
import { useState, type ReactNode } from "react";
2-
import { BuildingIcon, KeyIcon } from "./icons";
2+
import {
3+
AppleMark,
4+
BuildingIcon,
5+
FacebookMark,
6+
GitHubMark,
7+
GitLabMark,
8+
GoogleMark,
9+
KeyIcon,
10+
MicrosoftMark,
11+
} from "./icons";
312

413
export interface SSOProviderInfo {
514
label: string;
615
icon: ReactNode;
716
}
817

9-
const NON_BRAND_ICONS: Record<string, { label: string; icon: ReactNode }> = {
10-
passkey: { label: "Passkey", icon: <KeyIcon className="kma-sso-icon" /> },
11-
sso: { label: "SSO", icon: <BuildingIcon className="kma-sso-icon" /> },
12-
saml: { label: "SSO", icon: <BuildingIcon className="kma-sso-icon" /> },
18+
const BUILTIN_PROVIDERS: Record<
19+
string,
20+
{ label: string; Icon: (p: { className?: string }) => ReactNode }
21+
> = {
22+
google: { label: "Google", Icon: GoogleMark },
23+
github: { label: "GitHub", Icon: GitHubMark },
24+
gitlab: { label: "GitLab", Icon: GitLabMark },
25+
microsoft: { label: "Microsoft", Icon: MicrosoftMark },
26+
azure: { label: "Microsoft", Icon: MicrosoftMark },
27+
facebook: { label: "Facebook", Icon: FacebookMark },
28+
apple: { label: "Apple", Icon: AppleMark },
29+
passkey: { label: "Passkey", Icon: KeyIcon },
30+
sso: { label: "SSO", Icon: BuildingIcon },
31+
saml: { label: "SSO", Icon: BuildingIcon },
1332
};
1433

1534
function slugify(provider: string): string {
@@ -24,7 +43,7 @@ function titleCase(provider: string): string {
2443
.join(" ");
2544
}
2645

27-
function SSOProviderIcon({ provider }: { provider: string }) {
46+
function CDNProviderIcon({ provider }: { provider: string }) {
2847
const [errored, setErrored] = useState(false);
2948
const slug = slugify(provider);
3049
const letter = provider.trim().charAt(0).toUpperCase() || "?";
@@ -49,10 +68,17 @@ function SSOProviderIcon({ provider }: { provider: string }) {
4968

5069
export function getSSOProviderInfo(provider: string): SSOProviderInfo {
5170
const key = slugify(provider);
52-
const nonBrand = NON_BRAND_ICONS[key];
53-
if (nonBrand) return nonBrand;
71+
72+
const builtin = BUILTIN_PROVIDERS[key];
73+
if (builtin) {
74+
return {
75+
label: builtin.label,
76+
icon: <builtin.Icon className="kma-sso-icon" />,
77+
};
78+
}
79+
5480
return {
5581
label: titleCase(provider),
56-
icon: <SSOProviderIcon provider={provider} />,
82+
icon: <CDNProviderIcon provider={provider} />,
5783
};
5884
}

0 commit comments

Comments
 (0)