Skip to content

Commit 2b60bd9

Browse files
authored
ActivityPub onboarding step 2 (#22467)
ref AP-857 - Users might need help to understand the concept of ActivityPub which is why we implement a dedicated, step-by-step onboarding. This PR adds the 2nd step of it, that shows how notifications work.
1 parent 533bf2e commit 2b60bd9

File tree

7 files changed

+225
-78
lines changed

7 files changed

+225
-78
lines changed
Loading

apps/admin-x-activitypub/src/components/global/APAvatar.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ const APAvatar: React.FC<APAvatarProps> = ({author, size, isLoading = false, onC
5353
imageClass = clsx('h-10 w-10', imageClass);
5454
break;
5555
case 'md':
56-
containerClass = clsx('h-16 w-16', containerClass);
57-
imageClass = clsx('h-16 w-16', imageClass);
56+
containerClass = clsx('h-[60px] w-[60px]', containerClass);
57+
imageClass = clsx('h-[60px] w-[60px]', imageClass);
5858
break;
5959
case 'lg':
6060
containerClass = clsx('h-22 w-22', containerClass);

apps/admin-x-activitypub/src/components/layout/Onboarding/Onboarding.tsx

+2-20
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {useState} from 'react';
22
import Step1 from './Step1';
3+
import Step2 from './Step2';
34
import Step3 from './Step3';
4-
import {Button} from '@tryghost/shade';
55
import {parseAccessibilitySettings, updateAccessibilitySettings} from '@utils/accessibility';
66
import {useCurrentUser} from '@tryghost/admin-x-framework/api/currentUser';
77
import {useEditUser} from '@tryghost/admin-x-framework/api/users';
@@ -37,24 +37,6 @@ export const useOnboardingStatus = () => {
3737
return {isOnboarded, setOnboarded};
3838
};
3939

40-
const Step2: React.FC<{onNext: () => void}> = ({onNext}) => (
41-
<div className='relative h-full'>
42-
<div className='relative flex justify-between'>
43-
<div className='flex flex-col gap-4 text-xl font-medium'>
44-
<h1>Feel the network effect.</h1>
45-
<div className='flex max-w-[600px] flex-col gap-4'>
46-
<p className='text-gray-800 dark:text-gray-600'>People who follow you can like, reply, repost & interact with your work. Their followers will see those interactions too, distributing your content even more widely, to a brand new audience.</p>
47-
<p className='text-gray-800 dark:text-gray-600'>Best of all, you get realtime feedback and visibility when something you’ve created is spreading fast across the social web.</p>
48-
</div>
49-
</div>
50-
<Button className='min-w-60 bg-gradient-to-r from-purple-500 to-purple-600' size='lg' onClick={onNext}>Next →</Button>
51-
</div>
52-
<div className='mt-20'>
53-
Step 2 content
54-
</div>
55-
</div>
56-
);
57-
5840
const Onboarding: React.FC = () => {
5941
const {setOnboarded} = useOnboardingStatus();
6042
const [currentStep, setCurrentStep] = useState(1);
@@ -64,7 +46,7 @@ const Onboarding: React.FC = () => {
6446
};
6547

6648
return (
67-
<div className='h-full px-14 pt-14'>
49+
<div className='h-full pt-14'>
6850
{currentStep === 1 && (
6951
<Step1 onNext={() => setCurrentStep(2)} />
7052
)}

apps/admin-x-activitypub/src/components/layout/Onboarding/Step1.tsx

+51-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import APAvatar from '@src/components/global/APAvatar';
22
import React from 'react';
3+
import apNodes from '@assets/images/onboarding/ap-nodes.png';
34
import {Button, H3, LucideIcon} from '@tryghost/shade';
45
import {useAccountForUser} from '@src/hooks/use-activity-pub-queries';
56
import {useBrowseUsers} from '@tryghost/admin-x-framework/api/users';
@@ -11,57 +12,61 @@ const Step1: React.FC<{ onNext: () => void }> = ({onNext}) => {
1112

1213
return (
1314
<div className='relative h-full'>
14-
<div className='absolute inset-0 -mx-14 -mt-14 bg-[url(/ghost/assets/img/ap-nodes.png)] bg-cover bg-center bg-no-repeat' />
15-
<div className='relative flex justify-between'>
16-
<div className='flex flex-col gap-4 text-xl font-medium'>
17-
<h1 className='max-w-sm'>Increase your reach, with the social web.</h1>
18-
<div className='flex max-w-[600px] flex-col gap-4'>
19-
<p className='text-gray-800 dark:text-gray-600'>In addition to your website, email newsletter and RSS feeds, Ghost now shares posts to the social web – so millions of users across Flipboard, Mastodon, Threads, Bluesky and WordPress can find & follow your work.</p>
20-
<p><strong>{account?.name}</strong> is now part of the world’s largest open network.</p>
21-
</div>
22-
</div>
23-
<Button className={`min-w-60 bg-gradient-to-r from-purple-500 to-purple-600 ${!usersLoading && 'animate-onboarding-next-button'} opacity-0`} size='lg' onClick={onNext}>Next →</Button>
24-
</div>
25-
<div className='relative mx-auto mt-40 flex w-96 flex-col gap-3 rounded-lg bg-white p-6 shadow-xl'>
26-
<div className='flex items-start justify-between'>
27-
<APAvatar
28-
author={account && {
29-
icon: {
30-
url: account?.avatarUrl
31-
},
32-
name: account?.name,
33-
handle: account?.handle
34-
}}
35-
size='md'
36-
/>
37-
<span className='flex h-5 items-center gap-1 rounded-full bg-gray-100 px-3 text-[11px] font-medium uppercase text-gray-700 dark:bg-gray-925/70 dark:text-gray-500'>
38-
<LucideIcon.Check className='ml-[-2px]' size={14} />
39-
Following
40-
</span>
41-
</div>
42-
<div className='flex flex-col items-start gap-1'>
43-
<H3>{account?.name}</H3>
44-
<div className={`relative -ml-3 h-8 px-3 text-lg font-medium before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-[#CFB0FF] before:to-[#B6E8FF] before:opacity-0 ${!usersLoading && 'before:animate-onboarding-handle-bg'}`}>
45-
<div className='relative flex h-full items-center gap-1'>
46-
<span>{account?.handle}</span>
47-
<LucideIcon.Copy size={16} />
48-
<span className={`absolute right-full flex items-center gap-3 text-nowrap font-mono text-xs font-medium uppercase text-purple after:mr-3 after:h-[1.5px] after:w-24 after:scale-0 after:bg-purple after:content-[""] ${!usersLoading && 'after:animate-onboarding-handle-line'}`}><span className={`opacity-0 ${!usersLoading && 'animate-onboarding-handle-label'}`}>Your social web handle</span></span>
15+
<div className='isolate flex h-full flex-col items-stretch justify-between'>
16+
<div className='relative z-20 flex justify-between px-14'>
17+
<div className='flex flex-col gap-4 pb-20 text-xl font-medium'>
18+
<h1 className='max-w-sm'>Increase your reach, with the social web.</h1>
19+
<div className='flex max-w-[600px] flex-col gap-4'>
20+
<p className='text-gray-800 dark:text-gray-600'>In addition to your website, email newsletter and RSS feeds, Ghost now shares posts to the social web – so millions of users across Flipboard, Mastodon, Threads, Bluesky and WordPress can find & follow your work.</p>
21+
<p><strong>{account?.name}</strong> is now part of the world’s largest open network.</p>
4922
</div>
5023
</div>
24+
<Button className={`min-w-60 bg-gradient-to-r from-purple-500 to-[#6A1AD6] hover:opacity-90`} size='lg' onClick={onNext}>Next &rarr;</Button>
5125
</div>
52-
<p className='leading-tight text-gray-800 dark:text-gray-600'>{account?.bio}</p>
53-
<div className='mt-1 flex gap-2 text-sm text-gray-800 dark:text-gray-600'>
54-
<div className='flex [&>*:nth-child(1)]:z-30 [&>*:nth-child(2)]:z-20 [&>*:nth-child(3)]:z-10'>
55-
{firstThreeUsers.map((user, index) => (
56-
<img
57-
key={user.id}
58-
alt={user.name}
59-
className={`${index > 0 && '-ml-2'} relative h-5 w-5 rounded-full border border-white`}
60-
src={user.profile_image || '/default-avatar.png'}
26+
<div className='relative z-10 h-full'>
27+
<img className='absolute left-1/2 top-[calc(-280px)] w-full min-w-[1240px] max-w-[1300px] -translate-x-1/2' src={apNodes} />
28+
<div className='relative mx-auto mt-0 flex w-96 flex-col gap-3 rounded-lg bg-white p-6 shadow-xl xxl:mt-[calc(-280px+20vw)] min-[1800px]:mt-14'>
29+
<div className='flex items-start justify-between'>
30+
<APAvatar
31+
author={account && {
32+
icon: {
33+
url: account?.avatarUrl
34+
},
35+
name: account?.name,
36+
handle: account?.handle
37+
}}
38+
size='md'
6139
/>
62-
))}
40+
<span className='flex h-5 items-center gap-1 rounded-full bg-gray-100 px-3 text-[11px] font-medium uppercase text-gray-700 dark:bg-gray-925/70 dark:text-gray-500'>
41+
<LucideIcon.Check className='ml-[-2px]' size={14} />
42+
Following
43+
</span>
44+
</div>
45+
<div className='flex flex-col items-start gap-1'>
46+
<H3>{account?.name}</H3>
47+
<div className={`relative -ml-3 h-8 px-3 text-lg font-medium before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-[#CFB0FF66] before:to-[#B6E8FF66] before:opacity-0 ${!usersLoading && 'before:animate-onboarding-handle-bg'}`}>
48+
<div className='relative flex h-full items-center gap-1'>
49+
<span className='max-w-[316px] truncate'>{account?.handle}</span>
50+
<LucideIcon.Copy size={16} />
51+
<span className={`absolute right-full flex items-center gap-3 text-nowrap font-mono text-sm font-medium uppercase text-purple after:mr-3 after:h-[1.5px] after:w-24 after:scale-0 after:bg-purple after:content-[""] ${!usersLoading && 'after:animate-onboarding-handle-line'}`}><span className={`opacity-0 ${!usersLoading && 'animate-onboarding-handle-label'}`}>Your social web handle</span></span>
52+
</div>
53+
</div>
54+
</div>
55+
<p className='leading-tight text-gray-800 dark:text-gray-600'>{account?.bio}</p>
56+
<div className='mt-1 flex gap-2 text-sm text-gray-800 dark:text-gray-600'>
57+
<div className='flex [&>*:nth-child(1)]:z-30 [&>*:nth-child(2)]:z-20 [&>*:nth-child(3)]:z-10'>
58+
{firstThreeUsers.map((user, index) => (
59+
<img
60+
key={user.id}
61+
alt={user.name}
62+
className={`${index > 0 && '-ml-2'} relative h-5 w-5 rounded-full border border-white`}
63+
src={user.profile_image || '/default-avatar.png'}
64+
/>
65+
))}
66+
</div>
67+
Authored by {firstThreeUsers[0]?.name}{(meta?.pagination.total ?? 0) > 1 && ` and ${(meta?.pagination.total ?? 1) - 1} others`}
68+
</div>
6369
</div>
64-
Authored by {firstThreeUsers[0]?.name}{(meta?.pagination.total ?? 0) > 1 && ` and ${(meta?.pagination.total ?? 1) - 1} others`}
6570
</div>
6671
</div>
6772
</div>

0 commit comments

Comments
 (0)