diff --git a/assets/images/expensify-logo--adhoc.svg b/assets/images/expensify-logo--adhoc.svg
new file mode 100644
index 000000000000..63b6f896e3a5
--- /dev/null
+++ b/assets/images/expensify-logo--adhoc.svg
@@ -0,0 +1,47 @@
+
+
+
diff --git a/assets/images/expensify-logo--dev.svg b/assets/images/expensify-logo--dev.svg
new file mode 100644
index 000000000000..42a0f1d8e952
--- /dev/null
+++ b/assets/images/expensify-logo--dev.svg
@@ -0,0 +1,43 @@
+
+
+
diff --git a/assets/images/expensify-logo--staging.svg b/assets/images/expensify-logo--staging.svg
new file mode 100644
index 000000000000..335c41a294e3
--- /dev/null
+++ b/assets/images/expensify-logo--staging.svg
@@ -0,0 +1,46 @@
+
+
+
diff --git a/assets/images/home-background--desktop.svg b/assets/images/home-background--desktop.svg
new file mode 100644
index 000000000000..7241c46036c0
--- /dev/null
+++ b/assets/images/home-background--desktop.svg
@@ -0,0 +1,8839 @@
+
+
+
diff --git a/assets/images/home-background--mobile.svg b/assets/images/home-background--mobile.svg
new file mode 100644
index 000000000000..0af3aac59146
--- /dev/null
+++ b/assets/images/home-background--mobile.svg
@@ -0,0 +1,6556 @@
+
+
+
diff --git a/assets/images/home-fade-gradient--mobile.svg b/assets/images/home-fade-gradient--mobile.svg
new file mode 100644
index 000000000000..ca03eb3323af
--- /dev/null
+++ b/assets/images/home-fade-gradient--mobile.svg
@@ -0,0 +1,14 @@
+
+
+
diff --git a/assets/images/home-fade-gradient.svg b/assets/images/home-fade-gradient.svg
new file mode 100644
index 000000000000..6aada6633a8b
--- /dev/null
+++ b/assets/images/home-fade-gradient.svg
@@ -0,0 +1,14 @@
+
+
+
diff --git a/assets/images/product-illustrations/home-illustration-hands.svg b/assets/images/product-illustrations/home-illustration-hands.svg
new file mode 100644
index 000000000000..9a70d8cc6363
--- /dev/null
+++ b/assets/images/product-illustrations/home-illustration-hands.svg
@@ -0,0 +1,545 @@
+
+
+
diff --git a/src/components/ExpensifyWordmark.js b/src/components/ExpensifyWordmark.js
new file mode 100644
index 000000000000..11999dad22d2
--- /dev/null
+++ b/src/components/ExpensifyWordmark.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import {View} from 'react-native';
+import ProductionLogo from '../../assets/images/expensify-wordmark.svg';
+import DevLogo from '../../assets/images/expensify-logo--dev.svg';
+import StagingLogo from '../../assets/images/expensify-logo--staging.svg';
+import AdHocLogo from '../../assets/images/expensify-logo--adhoc.svg';
+import CONST from '../CONST';
+import withEnvironment, {environmentPropTypes} from './withEnvironment';
+import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
+import compose from '../libs/compose';
+import themeColors from '../styles/themes/default';
+import styles from '../styles/styles';
+import * as StyleUtils from '../styles/StyleUtils';
+import variables from '../styles/variables';
+
+const propTypes = {
+ ...environmentPropTypes,
+ ...windowDimensionsPropTypes,
+};
+
+const logoComponents = {
+ [CONST.ENVIRONMENT.DEV]: DevLogo,
+ [CONST.ENVIRONMENT.STAGING]: StagingLogo,
+ [CONST.ENVIRONMENT.PRODUCTION]: ProductionLogo,
+};
+
+const ExpensifyWordmark = (props) => {
+ // PascalCase is required for React components, so capitalize the const here
+ const LogoComponent = logoComponents[props.environment] || AdHocLogo;
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+ExpensifyWordmark.displayName = 'ExpensifyWordmark';
+ExpensifyWordmark.propTypes = propTypes;
+export default compose(
+ withEnvironment,
+ withWindowDimensions,
+)(ExpensifyWordmark);
diff --git a/src/components/Icon/Illustrations.js b/src/components/Icon/Illustrations.js
index 167d8e90f29f..0523fdbbc1e7 100644
--- a/src/components/Icon/Illustrations.js
+++ b/src/components/Icon/Illustrations.js
@@ -39,6 +39,7 @@ import ConciergeNew from '../../../assets/images/simple-illustrations/simple-ill
import MoneyBadge from '../../../assets/images/simple-illustrations/simple-illustration__moneybadge.svg';
import TreasureChest from '../../../assets/images/simple-illustrations/simple-illustration__treasurechest.svg';
import ThumbsUpStars from '../../../assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg';
+import Hands from '../../../assets/images/product-illustrations/home-illustration-hands.svg';
export {
Abracadabra,
@@ -82,4 +83,5 @@ export {
MoneyBadge,
TreasureChest,
ThumbsUpStars,
+ Hands,
};
diff --git a/src/components/LocalePicker.js b/src/components/LocalePicker.js
index 49aa459b728d..e61cef1379df 100644
--- a/src/components/LocalePicker.js
+++ b/src/components/LocalePicker.js
@@ -48,7 +48,7 @@ const LocalePicker = (props) => {
size={props.size}
value={props.preferredLocale}
containerStyles={props.size === 'small' ? [styles.pickerContainerSmall] : []}
- backgroundColor={themeColors.midtone}
+ backgroundColor={themeColors.signInPage}
/>
);
};
diff --git a/src/components/WelcomeText.js b/src/components/WelcomeText.js
deleted file mode 100755
index 0624f4061fbc..000000000000
--- a/src/components/WelcomeText.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import Text from './Text';
-
-const propTypes = {
-
- /** Fontsize */
- smallFontSize: PropTypes.bool,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- smallFontSize: false,
-};
-
-const WelcomeText = (props) => {
- const textSize = props.smallFontSize ? styles.textLabel : undefined;
- return (
- <>
-
- {props.translate('welcomeText.welcome')}
-
-
- {props.translate('welcomeText.phrase2')}
- {' '}
- {props.translate('welcomeText.phrase3')}
-
- >
- );
-};
-
-WelcomeText.displayName = 'WelcomeText';
-WelcomeText.propTypes = propTypes;
-WelcomeText.defaultProps = defaultProps;
-
-export default withLocalize(WelcomeText);
diff --git a/src/languages/en.js b/src/languages/en.js
index e50e86aba693..d58352933558 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -201,12 +201,20 @@ export default {
hello: 'Hello',
phoneCountryCode: '1',
welcomeText: {
- welcome: 'Welcome to New Expensify! Enter your phone number or email to continue.',
- welcomeEnterMagicCode: ({login}) => `It's always great to see a new face around here! Please enter the magic code sent to ${login}`,
+ getStarted: 'Get started below.',
+ welcomeBack: 'Welcome back!',
+ welcome: 'Welcome!',
phrase2: 'Money talks. And now that chat and payments are in one place, it\'s also easy.',
phrase3: 'Your payments get to you as fast as you can get your point across.',
- welcomeBack: 'Welcome back to the New Expensify! Please enter your password.',
- welcomeBackEnterMagicCode: ({login}) => `Welcome back! Please enter the magic code sent to ${login}`,
+ enterPassword: 'Please enter your password',
+ newFaceEnterMagicCode: ({login}) => `It's always great to see a new face around here! Please enter the magic code sent to ${login}`,
+ welcomeEnterMagicCode: ({login}) => `Please enter the magic code sent to ${login}`,
+ },
+ login: {
+ hero: {
+ header: 'Split bills, request payments, and chat with friends.',
+ body: 'Welcome to the future of Expensify, your new go-to place for financial collaboration with friends and teammates alike.',
+ },
},
reportActionCompose: {
addAction: 'Actions',
diff --git a/src/languages/es.js b/src/languages/es.js
index c3fa8eb065a2..348746f04b65 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -200,12 +200,20 @@ export default {
hello: 'Hola',
phoneCountryCode: '34',
welcomeText: {
- welcome: '¡Bienvenido al Nuevo Expensify! Por favor, introduce tu número de teléfono o email para continuar.',
- welcomeEnterMagicCode: ({login}) => `¡Siempre es genial ver una cara nueva por aquí! Por favor, introduce el código mágico enviado a ${login}`,
+ getStarted: 'Comience a continuación.',
+ welcomeBack: '¡Bienvenido de nuevo!',
+ welcome: '¡Bienvenido!',
phrase2: 'El dinero habla. Y ahora que chat y pagos están en un mismo lugar, es también fácil.',
phrase3: 'Tus pagos llegan tan rápido como tus mensajes.',
- welcomeBack: '¡Bienvenido de nuevo al Nuevo Expensify! Por favor, introduce tu contraseña.',
- welcomeBackEnterMagicCode: ({login}) => `¡Bienvenido de nuevo! Por favor, introduce el código mágico enviado a ${login}`,
+ enterPassword: 'Por favor, introduce tu contraseña',
+ newFaceEnterMagicCode: ({login}) => `¡Siempre es genial ver una cara nueva por aquí! Por favor ingresa el código mágico enviado a ${login}`,
+ welcomeEnterMagicCode: ({login}) => `Por favor, introduce el código mágico enviado a ${login}`,
+ },
+ login: {
+ hero: {
+ header: 'Divida las facturas, solicite pagos y chatee con sus amigos.',
+ body: 'Bienvenido al futuro de Expensify, tu nuevo lugar de referencia para la colaboración financiera con amigos y compañeros de equipo por igual.',
+ },
},
reportActionCompose: {
addAction: 'Acción',
diff --git a/src/pages/signin/SignInHeroCopy.js b/src/pages/signin/SignInHeroCopy.js
new file mode 100644
index 000000000000..f8ef85081691
--- /dev/null
+++ b/src/pages/signin/SignInHeroCopy.js
@@ -0,0 +1,37 @@
+import {View} from 'react-native';
+import React from 'react';
+import Text from '../../components/Text';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import compose from '../../libs/compose';
+import * as StyleUtils from '../../styles/StyleUtils';
+import styles from '../../styles/styles';
+import variables from '../../styles/variables';
+
+const propTypes = {
+ ...windowDimensionsPropTypes,
+ ...withLocalizePropTypes,
+};
+
+const SignInHeroCopy = props => (
+
+
+ {props.translate('login.hero.header')}
+
+
+ {props.translate('login.hero.body')}
+
+
+);
+
+SignInHeroCopy.displayName = 'SignInHeroCopy';
+SignInHeroCopy.propTypes = propTypes;
+
+export default compose(
+ withWindowDimensions,
+ withLocalize,
+)(SignInHeroCopy);
diff --git a/src/pages/signin/SignInHeroImage.js b/src/pages/signin/SignInHeroImage.js
new file mode 100644
index 000000000000..9167bd6ddb03
--- /dev/null
+++ b/src/pages/signin/SignInHeroImage.js
@@ -0,0 +1,44 @@
+import {View} from 'react-native';
+import React from 'react';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
+import * as Illustrations from '../../components/Icon/Illustrations';
+import styles from '../../styles/styles';
+import variables from '../../styles/variables';
+
+const propTypes = {
+ ...windowDimensionsPropTypes,
+};
+
+const SignInHeroImage = (props) => {
+ let imageSize;
+ if (props.isSmallScreenWidth) {
+ imageSize = {
+ height: variables.signInHeroImageMobileHeight,
+ width: variables.signInHeroImageMobileWidth,
+ };
+ } else if (props.isMediumScreenWidth) {
+ imageSize = {
+ height: variables.signInHeroImageTabletHeight,
+ width: variables.signInHeroImageTabletWidth,
+ };
+ } else {
+ imageSize = {
+ height: variables.signInHeroImageDesktopHeight,
+ width: variables.signInHeroImageDesktopWidth,
+ };
+ }
+
+ return (
+
+
+
+ );
+};
+
+SignInHeroImage.displayName = 'SignInHeroImage';
+SignInHeroImage.propTypes = propTypes;
+
+export default withWindowDimensions(SignInHeroImage);
diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js
index 53c4d5545485..f83f467106ee 100644
--- a/src/pages/signin/SignInPage.js
+++ b/src/pages/signin/SignInPage.js
@@ -16,6 +16,7 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize
import Performance from '../../libs/Performance';
import * as App from '../../libs/actions/App';
import Permissions from '../../libs/Permissions';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
import * as Localize from '../../libs/Localize';
const propTypes = {
@@ -41,6 +42,8 @@ const propTypes = {
}),
...withLocalizePropTypes,
+
+ ...windowDimensionsPropTypes,
};
const defaultProps = {
@@ -89,27 +92,44 @@ class SignInPage extends Component {
&& (!this.props.account.validated || this.props.account.forgotPassword)
&& !Permissions.canUsePasswordlessLogins(this.props.betas);
+ let welcomeHeader = '';
let welcomeText = '';
if (showValidateCodeForm) {
if (this.props.account.requiresTwoFactorAuth) {
// We will only know this after a user signs in successfully, without their 2FA code
+ welcomeHeader = this.props.isSmallScreenWidth ? '' : this.props.translate('welcomeText.welcomeBack');
welcomeText = this.props.translate('validateCodeForm.enterAuthenticatorCode');
} else {
const userLogin = Str.removeSMSDomain(lodashGet(this.props, 'credentials.login', ''));
- welcomeText = this.props.account.validated
- ? this.props.translate('welcomeText.welcomeBackEnterMagicCode', {login: userLogin})
- : this.props.translate('welcomeText.welcomeEnterMagicCode', {login: userLogin});
+
+ if (this.props.account.validated) {
+ welcomeHeader = this.props.isSmallScreenWidth ? '' : this.props.translate('welcomeText.welcomeBack');
+ welcomeText = this.props.isSmallScreenWidth
+ ? `${this.props.translate('welcomeText.welcomeBack')} ${this.props.translate('welcomeText.welcomeEnterMagicCode', {login: userLogin})}`
+ : this.props.translate('welcomeText.welcomeEnterMagicCode', {login: userLogin});
+ } else {
+ welcomeHeader = this.props.isSmallScreenWidth ? '' : this.props.translate('welcomeText.welcome');
+ welcomeText = this.props.isSmallScreenWidth
+ ? `${this.props.translate('welcomeText.welcome')} ${this.props.translate('welcomeText.newFaceEnterMagicCode', {login: userLogin})}`
+ : this.props.translate('welcomeText.newFaceEnterMagicCode', {login: userLogin});
+ }
}
} else if (showPasswordForm) {
- welcomeText = this.props.translate('welcomeText.welcomeBack');
+ welcomeHeader = this.props.isSmallScreenWidth ? '' : this.props.translate('welcomeText.welcomeBack');
+ welcomeText = this.props.isSmallScreenWidth
+ ? `${this.props.translate('welcomeText.welcomeBack')} ${this.props.translate('welcomeText.enterPassword')}`
+ : this.props.translate('welcomeText.enterPassword');
} else if (!showResendValidationForm) {
- welcomeText = this.props.translate('welcomeText.welcome');
+ welcomeHeader = this.props.isSmallScreenWidth ? this.props.translate('login.hero.header') : this.props.translate('welcomeText.getStarted');
+ welcomeText = this.props.isSmallScreenWidth ? this.props.translate('welcomeText.getStarted') : '';
}
return (
{/* LoginForm and PasswordForm must use the isVisible prop. This keeps them mounted, but visually hidden
@@ -132,6 +152,7 @@ SignInPage.defaultProps = defaultProps;
export default compose(
withLocalize,
+ withWindowDimensions,
withOnyx({
account: {key: ONYXKEYS.ACCOUNT},
betas: {key: ONYXKEYS.BETAS},
diff --git a/src/pages/signin/SignInPageHero.js b/src/pages/signin/SignInPageHero.js
new file mode 100644
index 000000000000..36edb388283a
--- /dev/null
+++ b/src/pages/signin/SignInPageHero.js
@@ -0,0 +1,34 @@
+import {View} from 'react-native';
+import React from 'react';
+import * as StyleUtils from '../../styles/StyleUtils';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
+import SignInHeroImage from './SignInHeroImage';
+import SignInHeroCopy from './SignInHeroCopy';
+import styles from '../../styles/styles';
+import variables from '../../styles/variables';
+
+const propTypes = {
+ ...windowDimensionsPropTypes,
+};
+
+const SignInPageHero = props => (
+
+
+
+
+
+
+);
+
+SignInPageHero.displayName = 'SignInPageHero';
+SignInPageHero.propTypes = propTypes;
+
+export default withWindowDimensions(SignInPageHero);
diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js
index 61b546d24be8..5fd421901f1d 100644
--- a/src/pages/signin/SignInPageLayout/Footer.js
+++ b/src/pages/signin/SignInPageLayout/Footer.js
@@ -4,6 +4,8 @@ import React from 'react';
import _ from 'underscore';
import Text from '../../../components/Text';
import styles from '../../../styles/styles';
+import * as StyleUtils from '../../../styles/StyleUtils';
+import themeColors from '../../../styles/themes/default';
import variables from '../../../styles/variables';
import * as Expensicons from '../../../components/Icon/Expensicons';
import TextLink from '../../../components/TextLink';
@@ -16,6 +18,7 @@ import Hoverable from '../../../components/Hoverable';
import CONST from '../../../CONST';
import Navigation, {navigationRef} from '../../../libs/Navigation/Navigation';
import * as Session from '../../../libs/actions/Session';
+import SignInGradient from '../../../../assets/images/home-fade-gradient--mobile.svg';
import screens from '../../../SCREENS';
const propTypes = {
@@ -170,13 +173,18 @@ const Footer = (props) => {
const imageDirection = isVertical ? styles.flexRow : styles.flexColumn;
const imageStyle = isVertical ? styles.pr0 : styles.alignSelfCenter;
const columnDirection = isVertical ? styles.flexColumn : styles.flexRow;
- const pageFooterWrapper = [styles.footerWrapper, imageDirection, imageStyle];
+ const pageFooterWrapper = [styles.footerWrapper, imageDirection, imageStyle, isVertical ? styles.pl10 : {}];
const footerColumns = [styles.footerColumnsContainer, columnDirection];
const footerColumn = isVertical ? [styles.p4] : [styles.p4, props.isMediumScreenWidth ? styles.w50 : styles.w25];
return (
-
+
+ {props.isSmallScreenWidth ? (
+
+
+
+ ) : null}
{_.map(columns, (column, i) => (
diff --git a/src/pages/signin/SignInPageLayout/SignInPageContent.js b/src/pages/signin/SignInPageLayout/SignInPageContent.js
index 76f03ec87715..34bbf8531d45 100755
--- a/src/pages/signin/SignInPageLayout/SignInPageContent.js
+++ b/src/pages/signin/SignInPageLayout/SignInPageContent.js
@@ -1,17 +1,18 @@
import React from 'react';
-import {ScrollView, View} from 'react-native';
+import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
import {withSafeAreaInsets} from 'react-native-safe-area-context';
import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
-import ExpensifyCashLogo from '../../../components/ExpensifyCashLogo';
+import ExpensifyWordmark from '../../../components/ExpensifyWordmark';
import Text from '../../../components/Text';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import SignInPageForm from '../../../components/SignInPageForm';
import compose from '../../../libs/compose';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import KeyboardAvoidingView from '../../../components/KeyboardAvoidingView';
import OfflineIndicator from '../../../components/OfflineIndicator';
+import SignInHeroImage from '../SignInHeroImage';
+import * as StyleUtils from '../../../styles/StyleUtils';
+import variables from '../../../styles/variables';
const propTypes = {
/** The children to show inside the layout */
@@ -21,9 +22,16 @@ const propTypes = {
* on form type (set password, sign in, etc.) */
welcomeText: PropTypes.string.isRequired,
+ /** Welcome header to show in the header of the form, changes depending
+ * on form type (set password, sign in, etc.) and small vs large screens */
+ welcomeHeader: PropTypes.string.isRequired,
+
/** Whether to show welcome text on a particular page */
shouldShowWelcomeText: PropTypes.bool.isRequired,
+ /** Whether to show welcome header on a particular page */
+ shouldShowWelcomeHeader: PropTypes.bool.isRequired,
+
...withLocalizePropTypes,
...windowDimensionsPropTypes,
};
@@ -34,42 +42,53 @@ const SignInPageContent = props => (
keyboardShouldPersistTaps="handled"
style={[!props.isSmallScreenWidth && styles.signInPageLeftContainerWide, styles.flex1]}
>
-
+
{/* This empty view creates margin on the top of the sign in form which will shrink and grow depending on if the keyboard is open or not */}
-
+
-
-
+
+
- {props.shouldShowWelcomeText && (
-
- {props.welcomeText}
-
+ {(props.shouldShowWelcomeHeader && props.welcomeHeader) ? (
+
+ {props.welcomeHeader}
+
+ ) : null}
+ {(props.shouldShowWelcomeText && props.welcomeText) ? (
+
+ {props.welcomeText}
+
+ ) : null}
- )}
{props.children}
+ {props.isSmallScreenWidth ? (
+ <>
+
+
+
+
+
+
+ >
+ ) : null}
-
-
-
+ {!props.isSmallScreenWidth ? (
+
+
+
+ ) : null}
);
diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js
index cd56d0c41fe4..f3e1a926639c 100644
--- a/src/pages/signin/SignInPageLayout/index.js
+++ b/src/pages/signin/SignInPageLayout/index.js
@@ -7,9 +7,14 @@ import SignInPageContent from './SignInPageContent';
import Footer from './Footer';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
import styles from '../../../styles/styles';
-import SignInPageGraphics from './SignInPageGraphics';
+import SignInPageHero from '../SignInPageHero';
import * as StyleUtils from '../../../styles/StyleUtils';
import scrollViewContentContainerStyles from './signInPageStyles';
+import themeColors from '../../../styles/themes/default';
+import SignInHeroBackgroundImage from '../../../../assets/images/home-background--desktop.svg';
+import SignInHeroBackgroundImageMobile from '../../../../assets/images/home-background--mobile.svg';
+import SignInGradient from '../../../../assets/images/home-fade-gradient.svg';
+import variables from '../../../styles/variables';
const propTypes = {
/** The children to show inside the layout */
@@ -19,9 +24,16 @@ const propTypes = {
* on form type (set password, sign in, etc.) */
welcomeText: PropTypes.string.isRequired,
+ /** Welcome header to show in the header of the form, changes depending
+ * on form type (set password, sign in, etc.) and small vs large screens */
+ welcomeHeader: PropTypes.string.isRequired,
+
/** Whether to show welcome text on a particular page */
shouldShowWelcomeText: PropTypes.bool.isRequired,
+ /** Whether to show welcome header on a particular page */
+ shouldShowWelcomeHeader: PropTypes.bool.isRequired,
+
...windowDimensionsPropTypes,
};
@@ -44,18 +56,40 @@ const SignInPageLayout = (props) => {
? (
{props.children}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
) : (
@@ -64,10 +98,17 @@ const SignInPageLayout = (props) => {
keyboardShouldPersistTaps="handled"
ref={scrollViewRef}
>
-
+
+
{props.children}
diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js
index 775ebeed563b..c92e0a8a8575 100644
--- a/src/styles/StyleUtils.js
+++ b/src/styles/StyleUtils.js
@@ -286,6 +286,26 @@ function getBackgroundColorStyle(backgroundColor) {
};
}
+/**
+ * Returns the width style for the wordmark logo on the sign in page
+ *
+ * @param {String} environment
+ * @param {Boolean} isSmallScreenWidth
+ * @returns {Object}
+ */
+function getSignInWordmarkWidthStyle(environment, isSmallScreenWidth) {
+ if (environment === CONST.ENVIRONMENT.DEV) {
+ return isSmallScreenWidth ? {width: variables.signInLogoWidthPill} : {width: variables.signInLogoWidthLargeScreenPill};
+ }
+ if (environment === CONST.ENVIRONMENT.STAGING) {
+ return isSmallScreenWidth ? {width: variables.signInLogoWidthPill} : {width: variables.signInLogoWidthLargeScreenPill};
+ }
+ if (environment === CONST.ENVIRONMENT.PRODUCTION) {
+ return isSmallScreenWidth ? {width: variables.signInLogoWidth} : {width: variables.signInLogoWidthLargeScreen};
+ }
+ return isSmallScreenWidth ? {width: variables.signInLogoWidthPill} : {width: variables.signInLogoWidthLargeScreenPill};
+}
+
/**
* Converts a color in hexadecimal notation into RGB notation.
*
@@ -691,6 +711,17 @@ function getMinimumHeight(minHeight) {
};
}
+/**
+ * Get maximum width as style
+ * @param {Number} maxWidth
+ * @returns {Object}
+ */
+function getMaximumWidth(maxWidth) {
+ return {
+ maxWidth,
+ };
+}
+
/**
* Return style for opacity animation.
*
@@ -789,6 +820,18 @@ function getReportWelcomeTopMarginStyle(isSmallScreenWidth) {
};
}
+/**
+ * Returns fontSize style
+ *
+ * @param {Number} fontSize
+ * @returns {Object}
+ */
+function getFontSizeStyle(fontSize) {
+ return {
+ fontSize,
+ };
+}
+
/**
* Gets the correct size for the empty state container based on screen dimensions
*
@@ -972,6 +1015,7 @@ export {
hasSafeAreas,
getHeight,
getMinimumHeight,
+ getMaximumWidth,
fade,
getHorizontalStackedAvatarBorderStyle,
getReportWelcomeBackgroundImageStyle,
@@ -986,4 +1030,6 @@ export {
getEmojiReactionBubbleTextStyle,
getEmojiReactionCounterTextStyle,
getDirectionStyle,
+ getFontSizeStyle,
+ getSignInWordmarkWidthStyle,
};
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 9c2eac87884a..7f848b6a953c 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -292,6 +292,10 @@ const styles = {
fontSize: variables.fontSizeExtraSmall,
},
+ textNormal: {
+ fontSize: variables.fontSizeNormal,
+ },
+
textLarge: {
fontSize: variables.fontSizeLarge,
},
@@ -1010,11 +1014,51 @@ const styles = {
},
signInPage: {
- backgroundColor: themeColors.sidebar,
+ backgroundColor: themeColors.highlightBG,
minHeight: '100%',
flex: 1,
},
+ signInPageHeroCenter: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+
+ signInPageGradient: {
+ height: '100%',
+ width: 540,
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ },
+
+ signInPageGradientMobile: {
+ height: 300,
+ width: 800,
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ },
+
+ signInBackgroundDesktop: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ minHeight: 700,
+ },
+
+ signInBackgroundMobile: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ minHeight: 700,
+ },
+
signInPageInner: {
marginLeft: 'auto',
marginRight: 'auto',
@@ -1033,7 +1077,7 @@ const styles = {
},
signInPageLeftContainerWide: {
- maxWidth: 360,
+ maxWidth: variables.sideBarWidth,
},
signInPageWelcomeFormContainer: {
@@ -3033,14 +3077,10 @@ const styles = {
fontSize: variables.fontSizeXXLarge,
letterSpacing: 4,
},
- footer: {
- backgroundColor: themeColors.midtone,
- },
footerWrapper: {
fontSize: variables.fontSizeNormal,
paddingTop: 64,
- paddingHorizontal: 32,
maxWidth: 1100, // Match footer across all Expensify platforms
},
@@ -3087,6 +3127,19 @@ const styles = {
top: 60,
zIndex: 100,
},
+ loginHeroHeader: {
+ fontFamily: fontFamily.EXP_NEW_KANSAS_MEDIUM,
+ color: themeColors.success,
+ fontWeight: '500',
+ textAlign: 'center',
+ },
+
+ loginHeroBody: {
+ fontFamily: fontFamily.EXP_NEUE,
+ fontSize: variables.fontSizeSignInHeroBody,
+ color: themeColors.textLight,
+ textAlign: 'center',
+ },
validateCodeMessage: {
width: variables.modalContentMaxWidth,
diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js
index c263bddd4ddf..67a30c0c0eb6 100644
--- a/src/styles/themes/default.js
+++ b/src/styles/themes/default.js
@@ -30,6 +30,7 @@ const darkTheme = {
successPressed: colors.greenPressed,
transparent: colors.transparent,
midtone: colors.green700,
+ signInPage: colors.green800,
dark: colors.midnight,
// Additional keys
@@ -39,6 +40,7 @@ const darkTheme = {
componentBG: colors.greenAppBackground,
hoverComponentBG: colors.greenHighlightBackground,
activeComponentBG: colors.greenBorders,
+ signInSidebar: colors.green800,
sidebar: colors.greenHighlightBackground,
sidebarHover: colors.greenAppBackground,
heading: colors.white,
diff --git a/src/styles/utilities/flex.js b/src/styles/utilities/flex.js
index 4de3409948a4..a8455a265d51 100644
--- a/src/styles/utilities/flex.js
+++ b/src/styles/utilities/flex.js
@@ -36,6 +36,9 @@ export default {
flexDirection: 'column',
},
+ flexColumnReverse: {
+ flexDirection: 'column-reverse',
+ },
justifyContentCenter: {
justifyContent: 'center',
},
diff --git a/src/styles/utilities/positioning.js b/src/styles/utilities/positioning.js
index 51a151ea72af..c893f3c697b7 100644
--- a/src/styles/utilities/positioning.js
+++ b/src/styles/utilities/positioning.js
@@ -9,6 +9,9 @@ export default {
pAbsolute: {
position: 'absolute',
},
+ t0: {
+ top: 0,
+ },
tn4: {
top: -16,
},
diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js
index 7e8b51529c7f..92445523120e 100644
--- a/src/styles/utilities/spacing.js
+++ b/src/styles/utilities/spacing.js
@@ -177,6 +177,10 @@ export default {
marginTop: 24,
},
+ mt8: {
+ marginTop: 32,
+ },
+
mb0: {
marginBottom: 0,
},
@@ -213,6 +217,10 @@ export default {
marginBottom: 32,
},
+ mb15: {
+ marginBottom: 60,
+ },
+
mbn1: {
marginBottom: -4,
},
@@ -314,6 +322,10 @@ export default {
paddingHorizontal: 40,
},
+ ph25: {
+ paddingHorizontal: 100,
+ },
+
pr0: {
paddingRight: 0,
},
@@ -358,6 +370,10 @@ export default {
paddingLeft: 20,
},
+ pl10: {
+ paddingLeft: 40,
+ },
+
pt0: {
paddingTop: 0,
},
@@ -386,6 +402,10 @@ export default {
paddingTop: 40,
},
+ pt20: {
+ paddingTop: 80,
+ },
+
pb1: {
paddingBottom: 4,
},
@@ -410,7 +430,16 @@ export default {
paddingBottom: 32,
},
+ pb20: {
+ paddingBottom: 80,
+ },
+
pb10Percentage: {
paddingBottom: '10%',
},
+
+ gap7: {
+ gap: 28,
+ },
+
};
diff --git a/src/styles/variables.js b/src/styles/variables.js
index c82d8286446a..b97aa3e0e1bc 100644
--- a/src/styles/variables.js
+++ b/src/styles/variables.js
@@ -48,11 +48,17 @@ export default {
fontSizeMedium: getValueUsingPixelRatio(16, 22),
fontSizeLarge: getValueUsingPixelRatio(17, 19),
fontSizeHero: 36,
+ fontSizeHeroXL: 72,
fontSizeh1: 19,
fontSizeXLarge: 22,
fontSizeXXLarge: 28,
fontSizeXXXLarge: 32,
fontSizeNormalHeight: getValueUsingPixelRatio(20, 28),
+ fontSizeSignInHeroLarge: 48,
+ fontSizeSignInHeroMedium: 38,
+ fontSizeSignInHeroXSmall: 26,
+ fontSizeSignInHeroSmall: 28,
+ fontSizeSignInHeroBody: 20,
lineHeightHero: 40,
iconSizeXXXSmall: 4,
iconSizeXXSmall: 8,
@@ -103,5 +109,22 @@ export default {
verticalLogoHeight: 634,
verticalLogoWidth: 111,
badgeMaxWidth: 180,
+ signInHeroImageMobileHeight: 240.08,
+ signInHeroImageMobileWidth: 303,
+ signInHeroImageTabletHeight: 324.01,
+ signInHeroImageTabletWidth: 346,
+ signInHeroImageDesktopHeight: 362.4,
+ signInHeroImageDesktopWidth: 386.99,
+ signInHeroBackgroundWidth: 2000,
+ signInHeroBackgroundWidthMobile: 800,
+ signInContentMaxWidth: 1360,
+ signInHeroContextMaxWidth: 740,
+ signInContentMinHeight: 800,
+ signInLogoHeightSmallScreen: 28,
+ signInLogoHeight: 34,
+ signInLogoWidth: 120,
+ signInLogoWidthLargeScreen: 144,
+ signInLogoWidthPill: 132,
+ signInLogoWidthLargeScreenPill: 162,
modalContentMaxWidth: 360,
};