mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
app: make the Home and auth pages reflow on mobile
This commit is contained in:
parent
64d0227452
commit
1c463439db
7 changed files with 69 additions and 12 deletions
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/icons/favicon-32x32.png" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="apple-touch-icon" sizes="48x48" href="%PUBLIC_URL%/icons/icon-48x48.png" />
|
||||
|
|
|
|||
|
|
@ -81,10 +81,12 @@
|
|||
font-display: swap;
|
||||
}
|
||||
|
||||
// the minimum width is not applied globally, since the Home and auth pages reflow
|
||||
// down to mobile widths. the pages which are laid out for desktop widths apply it
|
||||
// themselves via the Layout component
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
background-color: #252f4a;
|
||||
width: 100%;
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,17 @@ describe('AppView', () => {
|
|||
store = rootStore.appView;
|
||||
});
|
||||
|
||||
it('should only treat the Home page as responsive', () => {
|
||||
store.goToHome();
|
||||
expect(store.responsive).toBe(true);
|
||||
store.goToPool();
|
||||
expect(store.responsive).toBe(false);
|
||||
store.goToLoop();
|
||||
expect(store.responsive).toBe(false);
|
||||
store.goToSettings();
|
||||
expect(store.responsive).toBe(false);
|
||||
});
|
||||
|
||||
it('should add an alert', async () => {
|
||||
expect(store.alerts.size).toBe(0);
|
||||
store.notify('test message', 'test title');
|
||||
|
|
|
|||
|
|
@ -1,15 +1,25 @@
|
|||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { usePrefixedTranslation } from 'hooks';
|
||||
import QRCodeImg from 'qrcode.react';
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { Paragraph } from 'components/base';
|
||||
import Modal from 'components/common/Modal';
|
||||
|
||||
const Styled = {
|
||||
QRWrap: styled.div`
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
padding: 8px 8px 0;
|
||||
background-color: ${props => props.theme.colors.white};
|
||||
|
||||
/* the code is rendered as an svg so that it can scale down to fit inside of the
|
||||
modal on narrow screens, instead of being clipped by it */
|
||||
> svg {
|
||||
display: block;
|
||||
width: 500px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
|
|
@ -26,7 +36,7 @@ const QRCodeModal: React.FC<Props> = ({ url, visible, onClose }) => {
|
|||
<Modal title={l('title')} visible={visible} onClose={onClose}>
|
||||
<Paragraph space={32}>{l('desc')}</Paragraph>
|
||||
<QRWrap>
|
||||
<QRCodeImg value={url} size={500} />
|
||||
<QRCodeSVG value={url} size={500} />
|
||||
</QRWrap>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,24 +3,42 @@ import { observer } from 'mobx-react-lite';
|
|||
import styled from '@emotion/styled';
|
||||
import { usePrefixedTranslation } from 'hooks';
|
||||
import { useStore } from 'store';
|
||||
import { BoltOutlined, Button, Display, Paragraph, QRCode } from 'components/base';
|
||||
import { AUTO_COLLAPSE_MAX_WIDTH } from 'store/stores/settingsStore';
|
||||
import { BoltOutlined, Button, QRCode } from 'components/base';
|
||||
import { Display, Paragraph } from 'components/common/v2/Text';
|
||||
import PurpleButton from 'components/connect/PurpleButton';
|
||||
import QRCodeModal from 'components/connect/QRCodeModal';
|
||||
import YoutubeModal from './YoutubeModal';
|
||||
|
||||
const Styled = {
|
||||
Wrapper: styled.div`
|
||||
padding: 72px 0;
|
||||
/* while the sidebar is collapsed its toggle floats over the top of the page and
|
||||
the layout reserves space for it, so only a small amount of padding is added on
|
||||
top of that. the full padding is restored once the sidebar is displayed
|
||||
alongside the content again */
|
||||
padding: 16px 0 40px;
|
||||
|
||||
@media (min-width: ${AUTO_COLLAPSE_MAX_WIDTH + 1}px) {
|
||||
padding: 72px 0;
|
||||
}
|
||||
`,
|
||||
/* the connect buttons wrap onto multiple lines when the page is too narrow to fit
|
||||
them all on one line */
|
||||
Buttons: styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 24px;
|
||||
`,
|
||||
PurpleButton: styled(PurpleButton)`
|
||||
font-size: ${props => props.theme.sizes.s};
|
||||
line-height: 24px;
|
||||
padding: 8px 16px;
|
||||
margin-right: 24px;
|
||||
`,
|
||||
/* a text button which sits inline at the end of the description paragraph */
|
||||
LearnMoreButton: styled(Button)`
|
||||
font-family: ${props => props.theme.fonts.open.semiBold};
|
||||
/* inherit the metrics of the paragraph, which change on smaller screens */
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
vertical-align: baseline;
|
||||
padding: 0;
|
||||
|
|
@ -41,19 +59,19 @@ const HomePage: React.FC = () => {
|
|||
const closeQRModal = useCallback(() => setQrUrl(''), []);
|
||||
const toggleVideoModal = useCallback(() => setShowVideo(v => !v), []);
|
||||
|
||||
const { Wrapper, PurpleButton, LearnMoreButton } = Styled;
|
||||
const { Wrapper, Buttons, PurpleButton, LearnMoreButton } = Styled;
|
||||
return (
|
||||
<Wrapper>
|
||||
<Display semiBold space={16}>
|
||||
{l('pageTitle')}
|
||||
</Display>
|
||||
<Paragraph space={32}>
|
||||
<Paragraph space={24} desktopSpace={32}>
|
||||
{l('connectDesc')}
|
||||
<LearnMoreButton ghost borderless compact onClick={toggleVideoModal}>
|
||||
{l('learnMore')}
|
||||
</LearnMoreButton>
|
||||
</Paragraph>
|
||||
<Paragraph space={40}>
|
||||
<Buttons>
|
||||
<PurpleButton onClick={sessionStore.connectToTerminalWeb}>
|
||||
<BoltOutlined />
|
||||
{l('connectTerminalBtn')}
|
||||
|
|
@ -62,7 +80,7 @@ const HomePage: React.FC = () => {
|
|||
<QRCode />
|
||||
{l('connectQrBtn')}
|
||||
</PurpleButton>
|
||||
</Paragraph>
|
||||
</Buttons>
|
||||
<QRCodeModal url={qrUrl} visible={!!qrUrl} onClose={closeQRModal} />
|
||||
<YoutubeModal
|
||||
videoId="5kH1ByxjkTM"
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ const GlobalStyles = (theme: Theme) => `
|
|||
}
|
||||
`;
|
||||
|
||||
/** the width that the pages which do not reflow are laid out for */
|
||||
const DESKTOP_MIN_WIDTH = 1024;
|
||||
|
||||
/** the space the sidebar toggle occupies at the top of the page, including its offset */
|
||||
const HAMBURGER_HEIGHT = 80;
|
||||
|
||||
|
|
@ -65,12 +68,15 @@ const HAMBURGER_HEIGHT = 80;
|
|||
const SIDEBAR_WIDTH = 285;
|
||||
|
||||
const Styled = {
|
||||
Container: styled.div<{ fullWidth: boolean }>`
|
||||
Container: styled.div<{ fullWidth: boolean; responsive: boolean }>`
|
||||
position: relative;
|
||||
height: 100%;
|
||||
max-width: ${props => (props.fullWidth ? '100%' : '1440px')};
|
||||
width: ${props => (props.fullWidth ? '100%' : '100%')};
|
||||
margin: 0 auto;
|
||||
|
||||
/* pages which do not reflow scroll horizontally rather than being squeezed */
|
||||
${props => !props.responsive && `min-width: ${DESKTOP_MIN_WIDTH}px;`}
|
||||
`,
|
||||
Hamburger: styled.span<CollapsedProps>`
|
||||
display: inline-block;
|
||||
|
|
@ -163,7 +169,7 @@ export const Layout: React.FC = ({ children }) => {
|
|||
<Aside collapsed={!settingsStore.sidebarVisible}>
|
||||
<Sidebar />
|
||||
</Aside>
|
||||
<Container fullWidth={appView.fullWidth}>
|
||||
<Container fullWidth={appView.fullWidth} responsive={appView.responsive}>
|
||||
<Content collapsed={!settingsStore.sidebarVisible} fullWidth={appView.fullWidth}>
|
||||
<Fluid className="container-fluid">{children}</Fluid>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ export default class AppView {
|
|||
return this._store.router.location.pathname === `${PUBLIC_URL}/pool`;
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates if the current page reflows down to mobile widths. the remaining pages
|
||||
* contain tables and multi column sections which are laid out for desktop widths, so
|
||||
* they keep a minimum width and scroll horizontally instead of being squeezed
|
||||
*/
|
||||
get responsive() {
|
||||
return this._store.router.location.pathname === `${PUBLIC_URL}/home`;
|
||||
}
|
||||
|
||||
/** navigate to the specified route */
|
||||
goTo(route: string) {
|
||||
const path = `${PUBLIC_URL}${route}`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue