Merge branch 'login-ui' into 'main'

Move Login pages into the UI, delete AuthLayout

See merge request soapbox-pub/soapbox!2730
environments/review-main-yi2y9f/deployments/3980
Alex Gleason 2023-09-20 20:51:00 +00:00
commit 0d7c595818
19 zmienionych plików z 414 dodań i 554 usunięć

Wyświetl plik

@ -0,0 +1,32 @@
import React from 'react';
import { Card, CardBody, Stack, Text } from 'soapbox/components/ui';
interface IBigCard {
title: React.ReactNode
subtitle?: React.ReactNode
children: React.ReactNode
}
const BigCard: React.FC<IBigCard> = ({ title, subtitle, children }) => {
return (
<Card variant='rounded' size='xl'>
<CardBody>
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'>
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>{title}</Text>
{subtitle && <Text theme='muted' align='center'>{subtitle}</Text>}
</Stack>
</div>
<Stack space={5}>
<div className='mx-auto sm:w-2/3 sm:pt-10'>
{children}
</div>
</Stack>
</CardBody>
</Card>
);
};
export { BigCard };

Wyświetl plik

@ -17,7 +17,6 @@ import GdprBanner from 'soapbox/components/gdpr-banner';
import Helmet from 'soapbox/components/helmet'; import Helmet from 'soapbox/components/helmet';
import LoadingScreen from 'soapbox/components/loading-screen'; import LoadingScreen from 'soapbox/components/loading-screen';
import { StatProvider } from 'soapbox/contexts/stat-context'; import { StatProvider } from 'soapbox/contexts/stat-context';
import AuthLayout from 'soapbox/features/auth-layout';
import EmbeddedStatus from 'soapbox/features/embedded-status'; import EmbeddedStatus from 'soapbox/features/embedded-status';
import PublicLayout from 'soapbox/features/public-layout'; import PublicLayout from 'soapbox/features/public-layout';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
@ -104,11 +103,6 @@ const SoapboxMount = () => {
<Route exact path='/' component={PublicLayout} /> <Route exact path='/' component={PublicLayout} />
)} )}
<Route path='/login' component={AuthLayout} />
<Route path='/reset-password' component={AuthLayout} />
<Route path='/edit-password' component={AuthLayout} />
<Route path='/invite/:token' component={AuthLayout} />
<Route path='/' component={UI} /> <Route path='/' component={UI} />
</Switch> </Switch>
); );

Wyświetl plik

@ -1,89 +0,0 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Link, Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom';
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import { useOwnAccount, useInstance, useRegistrationStatus } from 'soapbox/hooks';
import { Button, Card, CardBody } from '../../components/ui';
import LoginPage from '../auth-login/components/login-page';
import PasswordReset from '../auth-login/components/password-reset';
import PasswordResetConfirm from '../auth-login/components/password-reset-confirm';
import ExternalLoginForm from '../external-login/components/external-login-form';
import Footer from '../public-layout/components/footer';
import RegisterInvite from '../register-invite';
const messages = defineMessages({
register: { id: 'auth_layout.register', defaultMessage: 'Create an account' },
});
const AuthLayout = () => {
const intl = useIntl();
const history = useHistory();
const { search } = useLocation();
const { account } = useOwnAccount();
const instance = useInstance();
const { isOpen } = useRegistrationStatus();
const isLoginPage = history.location.pathname === '/login';
return (
<div className='h-full'>
<LandingGradient />
<main className='relative h-full sm:flex sm:justify-center'>
<div className='flex h-full w-full flex-col sm:max-w-lg md:max-w-2xl lg:max-w-6xl'>
<header className='relative mb-auto flex justify-between px-2 py-12'>
<div className='relative z-0 flex-1 px-2 lg:absolute lg:inset-0 lg:flex lg:items-center lg:justify-center'>
<Link to='/' className='cursor-pointer'>
<SiteLogo alt={instance.title} className='h-7' />
</Link>
</div>
{(isLoginPage && isOpen) && (
<div className='relative z-10 ml-auto flex items-center'>
<Button
theme='tertiary'
icon={require('@tabler/icons/user.svg')}
to='/signup'
>
{intl.formatMessage(messages.register)}
</Button>
</div>
)}
</header>
<div className='flex flex-col items-center justify-center'>
<div className='w-full pb-10 sm:mx-auto sm:max-w-lg md:max-w-2xl'>
<Card variant='rounded' size='xl'>
<CardBody>
<Switch>
{/* If already logged in, redirect home. */}
{account && <Redirect from='/login' to='/' exact />}
<Route exact path='/login/external' component={ExternalLoginForm} />
<Route exact path='/login/add' component={LoginPage} />
<Route exact path='/login' component={LoginPage} />
<Route exact path='/reset-password' component={PasswordReset} />
<Route exact path='/edit-password' component={PasswordResetConfirm} />
<Route path='/invite/:token' component={RegisterInvite} />
<Redirect from='/auth/password/new' to='/reset-password' />
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
</Switch>
</CardBody>
</Card>
</div>
</div>
<div className='mt-auto'>
<Footer />
</div>
</div>
</main>
</div>
);
};
export default AuthLayout;

Wyświetl plik

@ -2,11 +2,9 @@ import React from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Button, Form, FormActions, FormGroup, Input, Stack } from 'soapbox/components/ui'; import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui';
import { useFeatures } from 'soapbox/hooks'; import { useFeatures } from 'soapbox/hooks';
import ConsumersList from './consumers-list';
const messages = defineMessages({ const messages = defineMessages({
username: { username: {
id: 'login.fields.username_label', id: 'login.fields.username_label',
@ -35,12 +33,6 @@ const LoginForm: React.FC<ILoginForm> = ({ isLoading, handleSubmit }) => {
const passwordLabel = intl.formatMessage(messages.password); const passwordLabel = intl.formatMessage(messages.password);
return ( return (
<div>
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'>
<h1 className='text-center text-2xl font-bold'><FormattedMessage id='login_form.header' defaultMessage='Sign In' /></h1>
</div>
<Stack className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2' space={5}>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<FormGroup labelText={usernameLabel}> <FormGroup labelText={usernameLabel}>
<Input <Input
@ -87,10 +79,6 @@ const LoginForm: React.FC<ILoginForm> = ({ isLoading, handleSubmit }) => {
</Button> </Button>
</FormActions> </FormActions>
</Form> </Form>
<ConsumersList />
</Stack>
</div>
); );
}; };

Wyświetl plik

@ -1,13 +1,16 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth'; import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { fetchInstance } from 'soapbox/actions/instance'; import { fetchInstance } from 'soapbox/actions/instance';
import { closeModal } from 'soapbox/actions/modals'; import { closeModal } from 'soapbox/actions/modals';
import { BigCard } from 'soapbox/components/big-card';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { getRedirectUrl } from 'soapbox/utils/redirect'; import { getRedirectUrl } from 'soapbox/utils/redirect';
import { isStandalone } from 'soapbox/utils/state'; import { isStandalone } from 'soapbox/utils/state';
import ConsumersList from './consumers-list';
import LoginForm from './login-form'; import LoginForm from './login-form';
import OtpAuthForm from './otp-auth-form'; import OtpAuthForm from './otp-auth-form';
@ -68,7 +71,12 @@ const LoginPage = () => {
if (mfaAuthNeeded) return <OtpAuthForm mfa_token={mfaToken} />; if (mfaAuthNeeded) return <OtpAuthForm mfa_token={mfaToken} />;
return <LoginForm handleSubmit={handleSubmit} isLoading={isLoading} />; return (
<BigCard title={<FormattedMessage id='login_form.header' defaultMessage='Sign In' />}>
<LoginForm handleSubmit={handleSubmit} isLoading={isLoading} />
<ConsumersList />
</BigCard>
);
}; };
export default LoginPage; export default LoginPage;

Wyświetl plik

@ -3,6 +3,7 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import { otpVerify, verifyCredentials, switchAccount } from 'soapbox/actions/auth'; import { otpVerify, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { BigCard } from 'soapbox/components/big-card';
import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui'; import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks'; import { useAppDispatch } from 'soapbox/hooks';
@ -47,14 +48,7 @@ const OtpAuthForm: React.FC<IOtpAuthForm> = ({ mfa_token }) => {
if (shouldRedirect) return <Redirect to='/' />; if (shouldRedirect) return <Redirect to='/' />;
return ( return (
<div> <BigCard title={<FormattedMessage id='login.otp_log_in' defaultMessage='OTP Login' />}>
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
<h1 className='text-center text-2xl font-bold'>
<FormattedMessage id='login.otp_log_in' defaultMessage='OTP Login' />
</h1>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<FormGroup <FormGroup
labelText={intl.formatMessage(messages.otpCodeLabel)} labelText={intl.formatMessage(messages.otpCodeLabel)}
@ -80,8 +74,7 @@ const OtpAuthForm: React.FC<IOtpAuthForm> = ({ mfa_token }) => {
</Button> </Button>
</FormActions> </FormActions>
</Form> </Form>
</div> </BigCard>
</div>
); );
}; };

Wyświetl plik

@ -3,6 +3,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import { resetPasswordConfirm } from 'soapbox/actions/security'; import { resetPasswordConfirm } from 'soapbox/actions/security';
import { BigCard } from 'soapbox/components/big-card';
import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui'; import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks'; import { useAppDispatch } from 'soapbox/hooks';
@ -55,14 +56,7 @@ const PasswordResetConfirm = () => {
} }
return ( return (
<div> <BigCard title={<FormattedMessage id='reset_password.header' defaultMessage='Set New Password' />}>
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
<h1 className='text-center text-2xl font-bold'>
<FormattedMessage id='reset_password.header' defaultMessage='Set New Password' />
</h1>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<FormGroup labelText={<FormattedMessage id='reset_password.password.label' defaultMessage='Password' />} errors={renderErrors()}> <FormGroup labelText={<FormattedMessage id='reset_password.password.label' defaultMessage='Password' />} errors={renderErrors()}>
<Input <Input
@ -80,8 +74,7 @@ const PasswordResetConfirm = () => {
</Button> </Button>
</FormActions> </FormActions>
</Form> </Form>
</div> </BigCard>
</div>
); );
}; };

Wyświetl plik

@ -3,6 +3,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import { resetPassword } from 'soapbox/actions/security'; import { resetPassword } from 'soapbox/actions/security';
import { BigCard } from 'soapbox/components/big-card';
import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui'; import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui';
import { useAppDispatch, useFeatures } from 'soapbox/hooks'; import { useAppDispatch, useFeatures } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
@ -36,14 +37,7 @@ const PasswordReset = () => {
if (success) return <Redirect to='/' />; if (success) return <Redirect to='/' />;
return ( return (
<div> <BigCard title={<FormattedMessage id='password_reset.header' defaultMessage='Reset Password' />}>
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-600 sm:-mx-10 sm:pb-10'>
<h1 className='text-center text-2xl font-bold'>
<FormattedMessage id='password_reset.header' defaultMessage='Reset Password' />
</h1>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<FormGroup labelText={intl.formatMessage(features.logInWithUsername ? messages.nicknameOrEmail : messages.email)}> <FormGroup labelText={intl.formatMessage(features.logInWithUsername ? messages.nicknameOrEmail : messages.email)}>
<Input <Input
@ -60,8 +54,7 @@ const PasswordReset = () => {
</Button> </Button>
</FormActions> </FormActions>
</Form> </Form>
</div> </BigCard>
</div>
); );
}; };

Wyświetl plik

@ -1,18 +1,15 @@
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Card, CardTitle, Stack } from 'soapbox/components/ui'; import { BigCard } from 'soapbox/components/big-card';
import RegistrationForm from './registration-form'; import RegistrationForm from './registration-form';
const RegistrationPage: React.FC = () => { const RegistrationPage: React.FC = () => {
return ( return (
<Card variant='rounded'> <BigCard title={<FormattedMessage id='column.registration' defaultMessage='Sign Up' />}>
<Stack space={2}>
<CardTitle title={<FormattedMessage id='column.registration' defaultMessage='Sign Up' />} />
<RegistrationForm /> <RegistrationForm />
</Stack> </BigCard>
</Card>
); );
}; };

Wyświetl plik

@ -1,10 +1,17 @@
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl';
import { BigCard } from 'soapbox/components/big-card';
import ExternalLoginForm from './components/external-login-form'; import ExternalLoginForm from './components/external-login-form';
/** Page for logging into a remote instance */ /** Page for logging into a remote instance */
const ExternalLoginPage: React.FC = () => { const ExternalLoginPage: React.FC = () => {
return <ExternalLoginForm />; return (
<BigCard title={<FormattedMessage id='login_form.header' defaultMessage='Sign In' />}>
<ExternalLoginForm />
</BigCard>
);
}; };
export default ExternalLoginPage; export default ExternalLoginPage;

Wyświetl plik

@ -3,7 +3,8 @@ import React from 'react';
import { defineMessages, FormattedMessage } from 'react-intl'; import { defineMessages, FormattedMessage } from 'react-intl';
import { patchMe } from 'soapbox/actions/me'; import { patchMe } from 'soapbox/actions/me';
import { Avatar, Button, Card, CardBody, Icon, Spinner, Stack, Text } from 'soapbox/components/ui'; import { BigCard } from 'soapbox/components/big-card';
import { Avatar, Button, Icon, Spinner, Stack } from 'soapbox/components/ui';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
import { isDefaultAvatar } from 'soapbox/utils/accounts'; import { isDefaultAvatar } from 'soapbox/utils/accounts';
@ -64,22 +65,10 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
}; };
return ( return (
<Card variant='rounded' size='xl'> <BigCard
<CardBody> title={<FormattedMessage id='onboarding.avatar.title' defaultMessage='Choose a profile picture' />}
<div> subtitle={<FormattedMessage id='onboarding.avatar.subtitle' defaultMessage='Just have fun with it.' />}
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-900/50 sm:-mx-10 sm:pb-10'> >
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>
<FormattedMessage id='onboarding.avatar.title' defaultMessage='Choose a profile picture' />
</Text>
<Text theme='muted' align='center'>
<FormattedMessage id='onboarding.avatar.subtitle' defaultMessage='Just have fun with it.' />
</Text>
</Stack>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Stack space={10}> <Stack space={10}>
<div className='relative mx-auto rounded-full bg-gray-200'> <div className='relative mx-auto rounded-full bg-gray-200'>
{account && ( {account && (
@ -123,10 +112,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
)} )}
</Stack> </Stack>
</Stack> </Stack>
</div> </BigCard>
</div>
</CardBody>
</Card>
); );
}; };

Wyświetl plik

@ -2,7 +2,8 @@ import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { patchMe } from 'soapbox/actions/me'; import { patchMe } from 'soapbox/actions/me';
import { Button, Card, CardBody, FormGroup, Stack, Text, Textarea } from 'soapbox/components/ui'; import { BigCard } from 'soapbox/components/big-card';
import { Button, FormGroup, Stack, Textarea } from 'soapbox/components/ui';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
@ -43,23 +44,12 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
}; };
return ( return (
<Card variant='rounded' size='xl'> <BigCard
<CardBody> title={<FormattedMessage id='onboarding.note.title' defaultMessage='Write a short bio' />}
<div> subtitle={<FormattedMessage id='onboarding.note.subtitle' defaultMessage='You can always edit this later.' />}
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'> >
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>
<FormattedMessage id='onboarding.note.title' defaultMessage='Write a short bio' />
</Text>
<Text theme='muted' align='center'>
<FormattedMessage id='onboarding.note.subtitle' defaultMessage='You can always edit this later.' />
</Text>
</Stack>
</div>
<Stack space={5}> <Stack space={5}>
<div className='mx-auto sm:w-2/3 sm:pt-10'> <div>
<FormGroup <FormGroup
hintText={<FormattedMessage id='onboarding.bio.hint' defaultMessage='Max 500 characters' />} hintText={<FormattedMessage id='onboarding.bio.hint' defaultMessage='Max 500 characters' />}
labelText={<FormattedMessage id='edit_profile.fields.bio_label' defaultMessage='Bio' />} labelText={<FormattedMessage id='edit_profile.fields.bio_label' defaultMessage='Bio' />}
@ -74,7 +64,7 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
</FormGroup> </FormGroup>
</div> </div>
<div className='mx-auto sm:w-2/3 md:w-1/2'> <div>
<Stack justifyContent='center' space={2}> <Stack justifyContent='center' space={2}>
<Button <Button
block block
@ -96,9 +86,7 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
</Stack> </Stack>
</div> </div>
</Stack> </Stack>
</div> </BigCard>
</CardBody>
</Card>
); );
}; };

Wyświetl plik

@ -3,8 +3,9 @@ import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { patchMe } from 'soapbox/actions/me'; import { patchMe } from 'soapbox/actions/me';
import { BigCard } from 'soapbox/components/big-card';
import StillImage from 'soapbox/components/still-image'; import StillImage from 'soapbox/components/still-image';
import { Avatar, Button, Card, CardBody, Icon, Spinner, Stack, Text } from 'soapbox/components/ui'; import { Avatar, Button, Icon, Spinner, Stack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
import { isDefaultHeader } from 'soapbox/utils/accounts'; import { isDefaultHeader } from 'soapbox/utils/accounts';
@ -67,22 +68,10 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
}; };
return ( return (
<Card variant='rounded' size='xl'> <BigCard
<CardBody> title={<FormattedMessage id='onboarding.header.title' defaultMessage='Pick a cover image' />}
<div> subtitle={<FormattedMessage id='onboarding.header.subtitle' defaultMessage='This will be shown at the top of your profile.' />}
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'> >
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>
<FormattedMessage id='onboarding.header.title' defaultMessage='Pick a cover image' />
</Text>
<Text theme='muted' align='center'>
<FormattedMessage id='onboarding.header.subtitle' defaultMessage='This will be shown at the top of your profile.' />
</Text>
</Stack>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Stack space={10}> <Stack space={10}>
<div className='rounded-lg border border-solid border-gray-200 dark:border-gray-800'> <div className='rounded-lg border border-solid border-gray-200 dark:border-gray-800'>
<div <div
@ -146,10 +135,7 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => {
)} )}
</Stack> </Stack>
</Stack> </Stack>
</div> </BigCard>
</div>
</CardBody>
</Card>
); );
}; };

Wyświetl plik

@ -2,7 +2,8 @@ import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { patchMe } from 'soapbox/actions/me'; import { patchMe } from 'soapbox/actions/me';
import { Button, Card, CardBody, FormGroup, Input, Stack, Text } from 'soapbox/components/ui'; import { BigCard } from 'soapbox/components/big-card';
import { Button, FormGroup, Input, Stack } from 'soapbox/components/ui';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
@ -54,22 +55,10 @@ const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
}; };
return ( return (
<Card variant='rounded' size='xl'> <BigCard
<CardBody> title={<FormattedMessage id='onboarding.display_name.title' defaultMessage='Choose a display name' />}
<div> subtitle={<FormattedMessage id='onboarding.display_name.subtitle' defaultMessage='You can always edit this later.' />}
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'> >
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>
<FormattedMessage id='onboarding.display_name.title' defaultMessage='Choose a display name' />
</Text>
<Text theme='muted' align='center'>
<FormattedMessage id='onboarding.display_name.subtitle' defaultMessage='You can always edit this later.' />
</Text>
</Stack>
</div>
<div className='mx-auto sm:w-2/3 sm:pt-10 md:w-1/2'>
<Stack space={5}> <Stack space={5}>
<FormGroup <FormGroup
hintText={hintText} hintText={hintText}
@ -105,10 +94,7 @@ const DisplayNameStep = ({ onNext }: { onNext: () => void }) => {
</Button> </Button>
</Stack> </Stack>
</Stack> </Stack>
</div> </BigCard>
</div>
</CardBody>
</Card>
); );
}; };

Wyświetl plik

@ -2,8 +2,9 @@ import debounce from 'lodash/debounce';
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { BigCard } from 'soapbox/components/big-card';
import ScrollableList from 'soapbox/components/scrollable-list'; import ScrollableList from 'soapbox/components/scrollable-list';
import { Button, Card, CardBody, Stack, Text } from 'soapbox/components/ui'; import { Button, Stack, Text } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container'; import AccountContainer from 'soapbox/containers/account-container';
import { useOnboardingSuggestions } from 'soapbox/queries/suggestions'; import { useOnboardingSuggestions } from 'soapbox/queries/suggestions';
@ -66,24 +67,12 @@ const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => {
}; };
return ( return (
<Card variant='rounded' size='xl'> <BigCard
<CardBody> title={<FormattedMessage id='onboarding.suggestions.title' defaultMessage='Suggested accounts' />}
<div> subtitle={<FormattedMessage id='onboarding.suggestions.subtitle' defaultMessage='Here are a few of the most popular accounts you might like.' />}
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'> >
<Stack space={2}>
<Text size='2xl' align='center' weight='bold'>
<FormattedMessage id='onboarding.suggestions.title' defaultMessage='Suggested accounts' />
</Text>
<Text theme='muted' align='center'>
<FormattedMessage id='onboarding.suggestions.subtitle' defaultMessage='Here are a few of the most popular accounts you might like.' />
</Text>
</Stack>
</div>
{renderBody()} {renderBody()}
<div className='mx-auto sm:w-2/3 md:w-1/2'>
<Stack> <Stack>
<Stack justifyContent='center' space={2}> <Stack justifyContent='center' space={2}>
<Button <Button
@ -99,10 +88,7 @@ const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => {
</Button> </Button>
</Stack> </Stack>
</Stack> </Stack>
</div> </BigCard>
</div>
</CardBody>
</Card>
); );
}; };

Wyświetl plik

@ -2,7 +2,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { Stack, CardTitle, Text } from 'soapbox/components/ui'; import { BigCard } from 'soapbox/components/big-card';
import RegistrationForm from 'soapbox/features/auth-login/components/registration-form'; import RegistrationForm from 'soapbox/features/auth-login/components/registration-form';
import { useInstance } from 'soapbox/hooks'; import { useInstance } from 'soapbox/hooks';
@ -23,21 +23,17 @@ const RegisterInvite: React.FC = () => {
/> />
); );
return ( const subtitle = (
<Stack space={3}>
<Stack className='mb-4'>
<CardTitle title={title} />
<Text theme='muted'>
<FormattedMessage <FormattedMessage
id='register_invite.lead' id='register_invite.lead'
defaultMessage='Complete the form below to create an account.' defaultMessage='Complete the form below to create an account.'
/> />
</Text> );
</Stack>
return (
<BigCard title={title} subtitle={subtitle}>
<RegistrationForm inviteToken={token} /> <RegistrationForm inviteToken={token} />
</Stack> </BigCard>
); );
}; };

Wyświetl plik

@ -18,13 +18,12 @@ import { Stack } from 'soapbox/components/ui';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status'; import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status';
import { HotKeys } from 'soapbox/features/ui/components/hotkeys'; import { HotKeys } from 'soapbox/features/ui/components/hotkeys';
import PendingStatus from 'soapbox/features/ui/components/pending-status'; import PendingStatus from 'soapbox/features/ui/components/pending-status';
import { useAppDispatch, useAppSelector, useOwnAccount, useSettings } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useSettings } from 'soapbox/hooks';
import { RootState } from 'soapbox/store'; import { RootState } from 'soapbox/store';
import { type Account, type Status } from 'soapbox/types/entities'; import { type Account, type Status } from 'soapbox/types/entities';
import { defaultMediaVisibility, textForScreenReader } from 'soapbox/utils/status'; import { defaultMediaVisibility, textForScreenReader } from 'soapbox/utils/status';
import DetailedStatus from './detailed-status'; import DetailedStatus from './detailed-status';
import ThreadLoginCta from './thread-login-cta';
import ThreadStatus from './thread-status'; import ThreadStatus from './thread-status';
type DisplayMedia = 'default' | 'hide_all' | 'show_all'; type DisplayMedia = 'default' | 'hide_all' | 'show_all';
@ -97,7 +96,6 @@ const Thread = (props: IThread) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const history = useHistory(); const history = useHistory();
const intl = useIntl(); const intl = useIntl();
const { account: me } = useOwnAccount();
const settings = useSettings(); const settings = useSettings();
const displayMedia = settings.get('displayMedia') as DisplayMedia; const displayMedia = settings.get('displayMedia') as DisplayMedia;
@ -459,8 +457,6 @@ const Thread = (props: IThread) => {
{children} {children}
</ScrollableList> </ScrollableList>
</div> </div>
{!me && <ThreadLoginCta />}
</Stack> </Stack>
); );
}; };

Wyświetl plik

@ -9,12 +9,13 @@ import {
} from 'soapbox/actions/statuses'; } from 'soapbox/actions/statuses';
import MissingIndicator from 'soapbox/components/missing-indicator'; import MissingIndicator from 'soapbox/components/missing-indicator';
import PullToRefresh from 'soapbox/components/pull-to-refresh'; import PullToRefresh from 'soapbox/components/pull-to-refresh';
import { Column } from 'soapbox/components/ui'; import { Column, Stack } from 'soapbox/components/ui';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status'; import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useLoggedIn } from 'soapbox/hooks';
import { makeGetStatus } from 'soapbox/selectors'; import { makeGetStatus } from 'soapbox/selectors';
import Thread from './components/thread'; import Thread from './components/thread';
import ThreadLoginCta from './components/thread-login-cta';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'status.title', defaultMessage: 'Post Details' }, title: { id: 'status.title', defaultMessage: 'Post Details' },
@ -47,6 +48,7 @@ interface IStatusDetails {
const StatusDetails: React.FC<IStatusDetails> = (props) => { const StatusDetails: React.FC<IStatusDetails> = (props) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const intl = useIntl(); const intl = useIntl();
const { isLoggedIn } = useLoggedIn();
const getStatus = useCallback(makeGetStatus(), []); const getStatus = useCallback(makeGetStatus(), []);
const status = useAppSelector((state) => getStatus(state, { id: props.params.statusId })); const status = useAppSelector((state) => getStatus(state, { id: props.params.statusId }));
@ -113,6 +115,7 @@ const StatusDetails: React.FC<IStatusDetails> = (props) => {
}; };
return ( return (
<Stack space={4}>
<Column label={intl.formatMessage(titleMessage())}> <Column label={intl.formatMessage(titleMessage())}>
<PullToRefresh onRefresh={handleRefresh}> <PullToRefresh onRefresh={handleRefresh}>
<Thread <Thread
@ -122,6 +125,9 @@ const StatusDetails: React.FC<IStatusDetails> = (props) => {
/> />
</PullToRefresh> </PullToRefresh>
</Column> </Column>
{!isLoggedIn && <ThreadLoginCta />}
</Stack>
); );
}; };

Wyświetl plik

@ -134,6 +134,11 @@ import {
FollowedTags, FollowedTags,
AboutPage, AboutPage,
RegistrationPage, RegistrationPage,
LoginPage,
PasswordReset,
PasswordResetConfirm,
RegisterInvite,
ExternalLogin,
} from './util/async-components'; } from './util/async-components';
import GlobalHotkeys from './util/global-hotkeys'; import GlobalHotkeys from './util/global-hotkeys';
import { WrappedRoute } from './util/react-router-helpers'; import { WrappedRoute } from './util/react-router-helpers';
@ -357,6 +362,15 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
<WrappedRoute path='/signup' page={DefaultPage} component={RegistrationPage} publicRoute exact /> <WrappedRoute path='/signup' page={DefaultPage} component={RegistrationPage} publicRoute exact />
)} )}
<WrappedRoute path='/login/external' page={DefaultPage} component={ExternalLogin} publicRoute exact />
<WrappedRoute path='/login/add' page={DefaultPage} component={LoginPage} publicRoute exact />
<WrappedRoute path='/login' page={DefaultPage} component={LoginPage} publicRoute exact />
<WrappedRoute path='/reset-password' page={DefaultPage} component={PasswordReset} publicRoute exact />
<WrappedRoute path='/edit-password' page={DefaultPage} component={PasswordResetConfirm} publicRoute exact />
<WrappedRoute path='/invite/:token' page={DefaultPage} component={RegisterInvite} publicRoute exact />
<Redirect from='/auth/password/new' to='/reset-password' />
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
<WrappedRoute page={EmptyPage} component={GenericNotFound} content={children} /> <WrappedRoute page={EmptyPage} component={GenericNotFound} content={children} />
</Switch> </Switch>
); );