0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-10 22:22:45 -05:00

style(ui): main page layout update (#2915)

This commit is contained in:
simeng-li 2023-01-16 17:24:14 +08:00 committed by GitHub
parent d559937e8b
commit 089b138c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 35 additions and 96 deletions

View file

@ -12,10 +12,14 @@
}
/* Main Layout */
.container {
.viewBox {
position: absolute;
inset: 0;
overflow: auto;
}
.container {
min-height: 100%;
@include _.flex_column(center, normal);
}
@ -29,6 +33,10 @@
}
:global(body.mobile) {
.container {
padding-bottom: env(safe-area-inset-bottom);
}
.main {
flex: 1;
align-self: stretch;
@ -36,6 +44,10 @@
position: relative;
background: var(--color-bg-body);
}
.placeHolder {
display: none;
}
}
:global(body.desktop) {
@ -47,6 +59,5 @@
border-radius: 16px;
background: var(--color-bg-float);
box-shadow: var(--color-shadow-2);
overflow: hidden;
}
}

View file

@ -1,20 +1,17 @@
import { useContext } from 'react';
import { Outlet } from 'react-router-dom';
import { PageContext } from '@/hooks/use-page-context';
import * as styles from './index.module.scss';
const AppContent = () => {
const { platform } = useContext(PageContext);
return (
<div className={styles.container}>
{platform === 'web' && <div className={styles.placeHolder} />}
<main className={styles.main}>
<Outlet />
</main>
{platform === 'web' && <div className={styles.placeHolder} />}
<div className={styles.viewBox}>
<div className={styles.container}>
<div className={styles.placeHolder} />
<main className={styles.main}>
<Outlet />
</main>
<div className={styles.placeHolder} />
</div>
</div>
);
};

View file

@ -1,43 +1,20 @@
import { fireEvent } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
import { socialConnectors } from '@/__mocks__/logto';
import SocialSignInList, { defaultSize } from '.';
import SocialSignInList from '.';
describe('SocialSignInList', () => {
it('less than three connectors', () => {
it('Display connectors', () => {
const { container } = renderWithPageContext(
<SettingsProvider>
<MemoryRouter>
<SocialSignInList socialConnectors={socialConnectors.slice(0, defaultSize)} />
<SocialSignInList socialConnectors={socialConnectors} />
</MemoryRouter>
</SettingsProvider>
);
expect(container.querySelectorAll('button')).toHaveLength(
socialConnectors.slice(0, defaultSize).length
);
});
it('more than three connectors', () => {
const { container } = renderWithPageContext(
<SettingsProvider>
<MemoryRouter>
<SocialSignInList isCollapseEnabled socialConnectors={socialConnectors} />
</MemoryRouter>
</SettingsProvider>
);
expect(container.querySelectorAll('button')).toHaveLength(defaultSize + 1); // Expand button
const expandButton = container.querySelector('svg');
if (expandButton) {
fireEvent.click(expandButton);
}
expect(container.querySelectorAll('button')).toHaveLength(socialConnectors.length + 1); // Expand button
expect(container.querySelectorAll('button')).toHaveLength(socialConnectors.length);
});
});

View file

@ -1,40 +1,23 @@
import type { ConnectorMetadata } from '@logto/schemas';
import classNames from 'classnames';
import { useState, useMemo } from 'react';
import ExpandIcon from '@/assets/icons/expand-icon.svg';
import IconButton from '@/components/Button/IconButton';
import SocialLinkButton from '@/components/Button/SocialLinkButton';
import useSocial from '@/hooks/use-social';
import { getLogoUrl } from '@/utils/logo';
import * as styles from './index.module.scss';
export const defaultSize = 4;
type Props = {
className?: string;
socialConnectors?: ConnectorMetadata[];
isCollapseEnabled?: boolean;
};
const SocialSignInList = ({ className, socialConnectors = [], isCollapseEnabled }: Props) => {
const [expand, setExpand] = useState(false);
const SocialSignInList = ({ className, socialConnectors = [] }: Props) => {
const { invokeSocialSignIn, theme } = useSocial();
const isOverSize = socialConnectors.length > defaultSize;
const displayAll = !isOverSize || !isCollapseEnabled;
const displayConnectors = useMemo(() => {
if (displayAll || expand) {
return socialConnectors;
}
return socialConnectors.slice(0, defaultSize);
}, [displayAll, expand, socialConnectors]);
return (
<div className={classNames(styles.socialLinkList, className)}>
{displayConnectors.map((connector) => {
{socialConnectors.map((connector) => {
const { id, name, logo: logoUrl, logoDark: darkLogoUrl, target } = connector;
return (
@ -50,16 +33,6 @@ const SocialSignInList = ({ className, socialConnectors = [], isCollapseEnabled
/>
);
})}
{!displayAll && (
<IconButton
className={classNames(styles.expandIcon, expand && styles.expanded)}
onClick={() => {
setExpand(!expand);
}}
>
<ExpandIcon />
</IconButton>
)}
</div>
);
};

View file

@ -15,13 +15,6 @@
flex: 1;
}
:global(body.mobile) {
.createAccount {
padding-bottom: env(safe-area-inset-bottom);
}
}
:global(body.desktop) {
.placeHolder {
flex: 0;

View file

@ -4,7 +4,6 @@ import { MemoryRouter } from 'react-router-dom';
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
import { mockSignInExperienceSettings } from '@/__mocks__/logto';
import { defaultSize } from '@/containers/SocialSignIn/SocialSignInList';
import Register from '@/pages/Register';
jest.mock('i18next', () => ({
@ -24,7 +23,9 @@ describe('<Register />', () => {
expect(container.querySelector('input[name="new-username"]')).not.toBeNull();
// Social
expect(queryAllByText('action.sign_in_with')).toHaveLength(defaultSize);
expect(queryAllByText('action.sign_in_with')).toHaveLength(
mockSignInExperienceSettings.socialConnectors.length
);
});
test('renders with email passwordless as primary', async () => {

View file

@ -41,11 +41,7 @@ const Register = () => {
signUpMethods.length > 0 && socialConnectors.length > 0 && (
<>
<Divider label="description.or" className={styles.divider} />
<SocialSignInList
isCollapseEnabled
socialConnectors={socialConnectors}
className={styles.main}
/>
<SocialSignInList socialConnectors={socialConnectors} className={styles.main} />
</>
)
}

View file

@ -17,12 +17,6 @@
}
:global(body.mobile) {
.createAccount {
padding-bottom: env(safe-area-inset-bottom);
}
}
:global(body.desktop) {
.placeHolder {
flex: 0;

View file

@ -8,7 +8,6 @@ import {
emailSignInMethod,
phoneSignInMethod,
} from '@/__mocks__/logto';
import { defaultSize } from '@/containers/SocialSignIn/SocialSignInList';
import SignIn from '@/pages/SignIn';
jest.mock('i18next', () => ({
@ -32,7 +31,9 @@ describe('<SignIn />', () => {
expect(queryByText('secondary.sign_in_with')).not.toBeNull();
// Social
expect(queryAllByText('action.sign_in_with')).toHaveLength(defaultSize);
expect(queryAllByText('action.sign_in_with')).toHaveLength(
mockSignInExperienceSettings.socialConnectors.length
);
});
test('renders with email passwordless as primary', async () => {

View file

@ -42,11 +42,7 @@ const SignIn = () => {
signInMethods.length > 0 && socialConnectors.length > 0 && (
<>
<Divider label="description.or" className={styles.divider} />
<SocialSignInList
isCollapseEnabled
socialConnectors={socialConnectors}
className={styles.main}
/>
<SocialSignInList socialConnectors={socialConnectors} className={styles.main} />
</>
)
}