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:
parent
d559937e8b
commit
089b138c77
10 changed files with 35 additions and 96 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -15,13 +15,6 @@
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
:global(body.mobile) {
|
||||
.createAccount {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
}
|
||||
|
||||
:global(body.desktop) {
|
||||
.placeHolder {
|
||||
flex: 0;
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,12 +17,6 @@
|
|||
}
|
||||
|
||||
|
||||
:global(body.mobile) {
|
||||
.createAccount {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
}
|
||||
|
||||
:global(body.desktop) {
|
||||
.placeHolder {
|
||||
flex: 0;
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue