Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions apps/ui/src/components/auth-actions/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/ui';
import { clsx } from 'clsx';
import { useLogin } from '@/data/queries/use-auth-user';
import { useOffline } from '@/hooks/use-offline';
import styles from './style.module.css';

interface AuthActionsProps {
className?: string;
}

// Shared by the welcome, tour and connect screens so the sign-in prompts
// can't drift apart.
export function AuthActions( { className }: AuthActionsProps ) {
const isOffline = useOffline();
const login = useLogin();
const signup = useLogin( { signup: true } );
const authError = login.error ?? signup.error;
const offlineMessage = __( "You're currently offline." );
const arrow = (
<span aria-hidden className={ styles.arrow }>
{ '↗' }
</span>
);

return (
<div className={ clsx( styles.root, className ) }>
<div className={ styles.actions }>
<Button
type="button"
variant="minimal"
tone="neutral"
disabled={ isOffline || login.isPending }
title={ isOffline ? offlineMessage : undefined }
loading={ signup.isPending }
onClick={ () => signup.mutate() }
>
{ __( 'Sign up' ) }
{ arrow }
</Button>
<Button
type="button"
variant="solid"
tone="brand"
disabled={ isOffline || signup.isPending }
title={ isOffline ? offlineMessage : undefined }
loading={ login.isPending }
onClick={ () => login.mutate() }
>
{ __( 'Log in with WordPress.com' ) }
{ arrow }
</Button>
</div>
{ authError && (
<p role="alert" className={ styles.error }>
{ authError instanceof Error
? authError.message
: __( 'Authentication failed. Please try again.' ) }
</p>
) }
</div>
);
}
41 changes: 41 additions & 0 deletions apps/ui/src/components/auth-actions/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.root {
display: flex;
flex-direction: column;
gap: 12px;
}

.actions {
display: flex;
align-items: center;
gap: 16px;
}

.actions > * {
flex-shrink: 0;
white-space: nowrap;
}

.arrow {
margin-inline-start: 4px;
display: inline-block;
}

[dir='rtl'] .arrow {
transform: scaleX(-1);
}

.error {
margin: 0;
padding: 10px 12px;
border: var(--wpds-border-width-xs) solid var(--wpds-color-stroke-surface-error);
border-radius: 6px;
background: var(--wpds-color-bg-surface-error-weak);
color: var(--wpds-color-fg-content-error);
}

@media (max-width: 600px) {
.actions {
align-items: stretch;
flex-direction: column;
}
}
27 changes: 27 additions & 0 deletions apps/ui/src/components/feature-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { check } from '@wordpress/icons';
import { Icon } from '@wordpress/ui';
import { clsx } from 'clsx';
import styles from './style.module.css';

interface FeatureListProps {
features: { title: string; body: string }[];
className?: string;
}

// The onboarding flow's checkmark feature columns, shared by the welcome
// screen and the tour steps so the two can't drift apart.
export function FeatureList( { features, className }: FeatureListProps ) {
return (
<ul className={ clsx( styles.features, className ) }>
{ features.map( ( { title, body } ) => (
<li key={ title }>
<h3 className={ styles.featureTitle }>
<Icon icon={ check } size={ 16 } />
{ title }
</h3>
<p className={ styles.featureBody }>{ body }</p>
</li>
) ) }
</ul>
);
}
44 changes: 44 additions & 0 deletions apps/ui/src/components/feature-list/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* Three left-aligned checkmark feature columns sharing one quiet bordered
container. Wider than the content column to make use of the horizontal
space. */
.features {
list-style: none;
margin: 16px 0 0;
padding: 16px 20px 20px;
border: var(--wpds-border-width-xs) solid var(--wpds-color-stroke-surface-neutral);
border-radius: 8px;
display: flex;
gap: 24px;
width: min(880px, calc(100vw - 100px));
text-align: start;
}

.features li {
flex: 1 1 0;
min-width: 0;
}

.featureTitle {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: var(--wpds-typography-font-weight-medium);
margin: 0 0 2px;
text-wrap: balance;
}

.featureTitle svg {
fill: var(--wpds-color-fg-interactive-brand);
flex-shrink: 0;
}

.featureBody {
color: var(--wpds-color-fg-content-neutral-weak);
font-size: 12px;
line-height: 1.4;
margin: 0;
/* Align with the title text, past the checkmark. */
margin-inline-start: 22px;
text-wrap: pretty;
}
Loading
Loading