diff --git a/packages/shared/src/components/icons/Bluesky/index.tsx b/packages/shared/src/components/icons/Bluesky/index.tsx
new file mode 100644
index 0000000000..5e5813d01c
--- /dev/null
+++ b/packages/shared/src/components/icons/Bluesky/index.tsx
@@ -0,0 +1,9 @@
+import type { ReactElement } from 'react';
+import React from 'react';
+import type { IconProps } from '../../Icon';
+import Icon from '../../Icon';
+import MonoIcon from './mono.svg';
+
+export const BlueskyIcon = (props: IconProps): ReactElement => (
+
+);
diff --git a/packages/shared/src/components/icons/Bluesky/mono.svg b/packages/shared/src/components/icons/Bluesky/mono.svg
new file mode 100644
index 0000000000..16b74284f1
--- /dev/null
+++ b/packages/shared/src/components/icons/Bluesky/mono.svg
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/packages/shared/src/components/icons/index.ts b/packages/shared/src/components/icons/index.ts
index e8ad5b43ed..18357ab6c2 100644
--- a/packages/shared/src/components/icons/index.ts
+++ b/packages/shared/src/components/icons/index.ts
@@ -8,6 +8,7 @@ export * from './Arrow';
export * from './At';
export * from './Bell';
export * from './Block';
+export * from './Bluesky';
export * from './Bookmark';
export * from './BringForward';
export * from './Calendar';
diff --git a/packages/shared/src/components/profile/ProfileWidgets.spec.tsx b/packages/shared/src/components/profile/ProfileWidgets.spec.tsx
index d2d5b6bbab..41151c87cd 100644
--- a/packages/shared/src/components/profile/ProfileWidgets.spec.tsx
+++ b/packages/shared/src/components/profile/ProfileWidgets.spec.tsx
@@ -44,6 +44,7 @@ const defaultLoggedUser: LoggedUser = {
youtube: 'idoshamun',
linkedin: 'idoshamun',
mastodon: 'https://mastodon.social/@idoshamun',
+ bluesky: 'https://bsky.app/profile/dailydotdev.bsky.social',
};
const defaultProfile: PublicProfile = {
@@ -69,6 +70,7 @@ const defaultProfile: PublicProfile = {
youtube: 'dailydotdev',
linkedin: 'dailydotdev',
mastodon: 'https://mastodon.social/@dailydotdev',
+ bluesky: 'https://bsky.app/profile/dailydotdev.bsky.social',
};
const defaultMemberships: Connection = {
@@ -289,6 +291,16 @@ it('should show mastodon link', () => {
expect(el).toHaveTextContent('mastodon.social/@dailydotdev');
});
+it('should show bluesky link', () => {
+ renderComponent();
+ const el = screen.getByTestId('bluesky');
+ expect(el).toHaveAttribute(
+ 'href',
+ 'https://bsky.app/profile/dailydotdev.bsky.social',
+ );
+ expect(el).toHaveTextContent('bsky.app/profile/dailydotdev.bsky.social');
+});
+
it('should show portfolio link', async () => {
renderComponent();
const el = screen.getByTestId('portfolio');
diff --git a/packages/shared/src/components/profile/SocialChips.tsx b/packages/shared/src/components/profile/SocialChips.tsx
index 74c1ee8b95..eb32002a04 100644
--- a/packages/shared/src/components/profile/SocialChips.tsx
+++ b/packages/shared/src/components/profile/SocialChips.tsx
@@ -10,6 +10,7 @@ import {
RedditIcon,
RoadmapIcon,
MastodonIcon,
+ BlueskyIcon,
ThreadsIcon,
CodePenIcon,
} from '../icons';
@@ -32,6 +33,7 @@ export interface SocialChipsProps {
youtube?: string;
linkedin?: string;
mastodon?: string;
+ bluesky?: string;
};
}
@@ -89,6 +91,11 @@ const handlers: Record<
href: (x) => x,
label: (x) => withoutProtocol(x),
},
+ bluesky: {
+ icon: ,
+ href: (x) => x,
+ label: (x) => `https://bsky.app/profile/${x}`,
+ },
threads: {
icon: ,
href: (x) => `https://threads.net/@${x}`,
@@ -111,6 +118,7 @@ const order: (keyof SocialChipsProps['links'])[] = [
'roadmap',
'codepen',
'mastodon',
+ 'bluesky',
'threads',
];
diff --git a/packages/shared/src/graphql/users.ts b/packages/shared/src/graphql/users.ts
index c2b50e448d..0cdf1186dc 100644
--- a/packages/shared/src/graphql/users.ts
+++ b/packages/shared/src/graphql/users.ts
@@ -45,6 +45,7 @@ export const USER_BY_ID_STATIC_FIELDS_QUERY = `
youtube
linkedin
mastodon
+ bluesky
timezone
portfolio
reputation
@@ -304,6 +305,7 @@ export const UPDATE_USER_PROFILE_MUTATION = gql`
youtube
linkedin
mastodon
+ bluesky
createdAt
infoConfirmed
timezone
diff --git a/packages/shared/src/hooks/useProfileForm.ts b/packages/shared/src/hooks/useProfileForm.ts
index 48aac6b05c..0a46a89d54 100644
--- a/packages/shared/src/hooks/useProfileForm.ts
+++ b/packages/shared/src/hooks/useProfileForm.ts
@@ -27,6 +27,7 @@ export interface ProfileFormHint {
youtube?: string;
linkedin?: string;
mastodon?: string;
+ bluesky?: string;
}
export interface UpdateProfileParameters extends Partial {
@@ -64,6 +65,7 @@ type Handles = Pick<
| 'youtube'
| 'linkedin'
| 'mastodon'
+ | 'bluesky'
>;
const socials: Array = [
'github',
@@ -77,6 +79,7 @@ const socials: Array = [
'youtube',
'linkedin',
'mastodon',
+ 'bluesky',
];
export const onValidateHandles = (
diff --git a/packages/shared/src/lib/user.ts b/packages/shared/src/lib/user.ts
index cfaff3fbce..100d9dc417 100644
--- a/packages/shared/src/lib/user.ts
+++ b/packages/shared/src/lib/user.ts
@@ -39,6 +39,7 @@ export interface PublicProfile {
youtube?: string;
linkedin?: string;
mastodon?: string;
+ bluesky?: string;
bio?: string;
createdAt: string;
premium: boolean;
@@ -81,6 +82,7 @@ export interface UserProfile {
youtube?: string;
linkedin?: string;
mastodon?: string;
+ bluesky?: string;
portfolio?: string;
bio?: string;
acceptedMarketing?: boolean;
diff --git a/packages/webapp/__tests__/AccountProfilePage.tsx b/packages/webapp/__tests__/AccountProfilePage.tsx
index dd5eb4c111..f8b3e2948b 100644
--- a/packages/webapp/__tests__/AccountProfilePage.tsx
+++ b/packages/webapp/__tests__/AccountProfilePage.tsx
@@ -36,6 +36,7 @@ const defaultLoggedUser: LoggedUser = {
youtube: 'dailydotdev',
linkedin: 'dailydotdev',
mastodon: 'https://mastodon.social/@dailydotdev',
+ bluesky: 'https://bsky.app/profile/dailydotdev.bsky.social',
};
const updateUser = jest.fn();
@@ -122,4 +123,7 @@ it('should show profile social links', () => {
const mastodon = screen.getByPlaceholderText('Mastodon');
expect(mastodon).toBeInTheDocument();
expect(mastodon).toHaveValue(defaultLoggedUser.mastodon);
+ const bluesky = screen.getByPlaceholderText('Bluesky');
+ expect(bluesky).toBeInTheDocument();
+ expect(bluesky).toHaveValue(defaultLoggedUser.bluesky);
});
diff --git a/packages/webapp/components/layouts/AccountLayout/Profile/index.tsx b/packages/webapp/components/layouts/AccountLayout/Profile/index.tsx
index fe7b07c03c..9f4d1f49dd 100644
--- a/packages/webapp/components/layouts/AccountLayout/Profile/index.tsx
+++ b/packages/webapp/components/layouts/AccountLayout/Profile/index.tsx
@@ -13,6 +13,7 @@ import {
LinkedInIcon,
LinkIcon,
MastodonIcon,
+ BlueskyIcon,
RedditIcon,
RoadmapIcon,
StackOverflowIcon,
@@ -88,6 +89,7 @@ const ProfileIndex = ({
youtube: values.youtube,
linkedin: values.linkedin,
mastodon: values.mastodon ? withHttps(values.mastodon) : null,
+ bluesky: values.bluesky,
experienceLevel: values.experienceLevel,
onUpdateSuccess: () =>
router.push(`/${values.username}`).then(() => {
@@ -285,7 +287,6 @@ const ProfileIndex = ({
hint={hint.portfolio}
valid={!hint.portfolio}
name="portfolio"
- type="url"
value={user?.portfolio}
placeholder="example.com"
/>
@@ -356,10 +357,19 @@ const ProfileIndex = ({
hint={hint.mastodon}
valid={!hint.mastodon}
name="mastodon"
- type="url"
value={user?.mastodon}
placeholder="mastodon.social/@username"
/>
+ }
+ label="Bluesky"
+ inputId="bluesky"
+ hint={hint.bluesky}
+ valid={!hint.bluesky}
+ name="bluesky"
+ value={user?.bluesky}
+ placeholder="bsky.app/profile/username"
+ />
}
label="Threads"