rework login page
This commit is contained in:
parent
18e09b81a2
commit
fdf447c9cb
12 changed files with 92 additions and 107 deletions
|
|
@ -1,12 +0,0 @@
|
|||
import { style } from '@vanilla-extract/css';
|
||||
import { color, config } from 'folds';
|
||||
|
||||
export const SplashScreen = style({
|
||||
minHeight: '100%',
|
||||
backgroundColor: color.Background.Container,
|
||||
color: color.Background.OnContainer,
|
||||
});
|
||||
|
||||
export const SplashScreenFooter = style({
|
||||
padding: config.space.S400,
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import { Box, Text } from 'folds';
|
||||
import React, { ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import * as patternsCSS from '../../styles/Patterns.css';
|
||||
import * as css from './SplashScreen.css';
|
||||
|
||||
type SplashScreenProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
export function SplashScreen({ children }: SplashScreenProps) {
|
||||
return (
|
||||
<Box
|
||||
className={classNames(css.SplashScreen, patternsCSS.BackgroundDotPattern)}
|
||||
direction="Column"
|
||||
>
|
||||
{children}
|
||||
<Box
|
||||
className={css.SplashScreenFooter}
|
||||
shrink="No"
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
>
|
||||
<Text size="H2" align="Center">
|
||||
Vojo
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './SplashScreen';
|
||||
|
|
@ -1,16 +1,9 @@
|
|||
import { Box, Button, Dialog, Spinner, Text, color, config } from 'folds';
|
||||
import { Box, Button, Dialog, Text, color, config } from 'folds';
|
||||
import React from 'react';
|
||||
import { SplashScreen } from '../components/splash-screen';
|
||||
import { AuthSplashScreen } from './auth/AuthSplashScreen';
|
||||
|
||||
export function ConfigConfigLoading() {
|
||||
return (
|
||||
<SplashScreen>
|
||||
<Box grow="Yes" direction="Column" gap="400" alignItems="Center" justifyContent="Center">
|
||||
<Spinner variant="Secondary" size="600" />
|
||||
<Text>Heating up</Text>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
);
|
||||
return <AuthSplashScreen />;
|
||||
}
|
||||
|
||||
type ConfigConfigErrorProps = {
|
||||
|
|
@ -20,7 +13,7 @@ type ConfigConfigErrorProps = {
|
|||
};
|
||||
export function ConfigConfigError({ error, retry, ignore }: ConfigConfigErrorProps) {
|
||||
return (
|
||||
<SplashScreen>
|
||||
<AuthSplashScreen>
|
||||
<Box grow="Yes" direction="Column" gap="400" alignItems="Center" justifyContent="Center">
|
||||
<Dialog>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
|
|
@ -48,6 +41,6 @@ export function ConfigConfigError({ error, retry, ignore }: ConfigConfigErrorPro
|
|||
</Box>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
</AuthSplashScreen>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { ReactNode, useEffect } from 'react';
|
|||
import { Box, Dialog, Text, config } from 'folds';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { checkIndexedDBSupport } from '../utils/featureCheck';
|
||||
import { SplashScreen } from '../components/splash-screen';
|
||||
import { AuthSplashScreen } from './auth/AuthSplashScreen';
|
||||
|
||||
export function FeatureCheck({ children }: { children: ReactNode }) {
|
||||
const [idbSupportState, checkIDBSupport] = useAsyncCallback(checkIndexedDBSupport);
|
||||
|
|
@ -13,7 +13,7 @@ export function FeatureCheck({ children }: { children: ReactNode }) {
|
|||
|
||||
if (idbSupportState.status === AsyncStatus.Success && idbSupportState.data === false) {
|
||||
return (
|
||||
<SplashScreen>
|
||||
<AuthSplashScreen>
|
||||
<Box grow="Yes" alignItems="Center" justifyContent="Center">
|
||||
<Dialog>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
|
|
@ -34,7 +34,7 @@ export function FeatureCheck({ children }: { children: ReactNode }) {
|
|||
</Box>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
</AuthSplashScreen>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { AuthFooter } from './AuthFooter';
|
||||
import { AuthMascot } from './AuthMascot';
|
||||
import { authLayoutRootVars } from './layoutConfig';
|
||||
import * as css from './styles.css';
|
||||
import {
|
||||
clientAllowedServer,
|
||||
|
|
@ -27,8 +29,6 @@ import { AuthFlowsLoader } from '../../components/AuthFlowsLoader';
|
|||
import { AuthFlowsProvider } from '../../hooks/useAuthFlows';
|
||||
import { AuthServerProvider } from '../../hooks/useAuthServer';
|
||||
import { tryDecodeURIComponent } from '../../utils/dom';
|
||||
import mascotPoster from '../../../../public/res/img/mascot.png';
|
||||
import mascotWebm from '../../../../public/res/img/mascot.webm';
|
||||
|
||||
const currentAuthPath = (pathname: string): string => {
|
||||
if (matchPath(LOGIN_PATH, pathname)) return LOGIN_PATH;
|
||||
|
|
@ -163,16 +163,6 @@ function calculateModalLayout(input: {
|
|||
};
|
||||
}
|
||||
|
||||
const rootVars: React.CSSProperties = {
|
||||
'--vojo-mascot-size': 'clamp(28rem, 57dvh, 48rem)',
|
||||
'--vojo-mascot-top': 'clamp(1.5rem, 4dvh, 3rem)',
|
||||
'--vojo-stack-pad': '1.5rem',
|
||||
'--vojo-anchor-ratio': '0.71',
|
||||
'--vojo-modal-min-top': 'clamp(12rem, 26dvh, 18rem)',
|
||||
'--vojo-modal-gap': 'clamp(0.75rem, 2dvh, 1.5rem)',
|
||||
'--vojo-footer-space': 'clamp(4.5rem, 9dvh, 6.5rem)',
|
||||
} as React.CSSProperties;
|
||||
|
||||
export function AuthLayout() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
|
@ -291,21 +281,9 @@ export function AuthLayout() {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className={css.AuthLayout} style={rootVars} ref={pageRef}>
|
||||
<div className={css.AuthLayout} style={authLayoutRootVars} ref={pageRef}>
|
||||
<div className={css.AuthStack}>
|
||||
<div className={css.AuthMascot} aria-hidden="true" ref={mascotRef}>
|
||||
<video
|
||||
className={css.AuthMascotVideo}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
preload="auto"
|
||||
poster={mascotPoster}
|
||||
>
|
||||
<source src={mascotWebm} type="video/webm" />
|
||||
</video>
|
||||
</div>
|
||||
<AuthMascot mascotRef={mascotRef} />
|
||||
|
||||
<div className={css.AuthModalZone}>
|
||||
<div className={css.AuthCard} ref={modalRef}>
|
||||
|
|
|
|||
27
src/app/pages/auth/AuthMascot.tsx
Normal file
27
src/app/pages/auth/AuthMascot.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React, { Ref } from 'react';
|
||||
|
||||
import mascotPoster from '../../../../public/res/img/mascot.png';
|
||||
import mascotWebm from '../../../../public/res/img/mascot.webm';
|
||||
import * as css from './styles.css';
|
||||
|
||||
type AuthMascotProps = {
|
||||
mascotRef?: Ref<HTMLDivElement>;
|
||||
};
|
||||
|
||||
export function AuthMascot({ mascotRef }: AuthMascotProps) {
|
||||
return (
|
||||
<div className={css.AuthMascot} aria-hidden="true" ref={mascotRef}>
|
||||
<video
|
||||
className={css.AuthMascotVideo}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
preload="auto"
|
||||
poster={mascotPoster}
|
||||
>
|
||||
<source src={mascotWebm} type="video/webm" />
|
||||
</video>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
22
src/app/pages/auth/AuthSplashScreen.tsx
Normal file
22
src/app/pages/auth/AuthSplashScreen.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
|
||||
import { AuthFooter } from './AuthFooter';
|
||||
import { AuthMascot } from './AuthMascot';
|
||||
import { authLayoutRootVars } from './layoutConfig';
|
||||
import * as css from './styles.css';
|
||||
|
||||
type AuthSplashScreenProps = {
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
export function AuthSplashScreen({ children }: AuthSplashScreenProps) {
|
||||
return (
|
||||
<div className={css.AuthLayout} style={authLayoutRootVars}>
|
||||
<div className={css.AuthStack}>
|
||||
<AuthMascot />
|
||||
{children && <div className={css.AuthSplashContent}>{children}</div>}
|
||||
</div>
|
||||
<AuthFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
11
src/app/pages/auth/layoutConfig.ts
Normal file
11
src/app/pages/auth/layoutConfig.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import type { CSSProperties } from 'react';
|
||||
|
||||
export const authLayoutRootVars: CSSProperties = {
|
||||
'--vojo-mascot-size': 'clamp(28rem, 57dvh, 48rem)',
|
||||
'--vojo-mascot-top': 'clamp(1.5rem, 4dvh, 3rem)',
|
||||
'--vojo-stack-pad': '1.5rem',
|
||||
'--vojo-anchor-ratio': '0.71',
|
||||
'--vojo-modal-min-top': 'clamp(12rem, 26dvh, 18rem)',
|
||||
'--vojo-modal-gap': 'clamp(0.75rem, 2dvh, 1.5rem)',
|
||||
'--vojo-footer-space': 'clamp(4.5rem, 9dvh, 6.5rem)',
|
||||
} as CSSProperties;
|
||||
|
|
@ -87,6 +87,17 @@ export const AuthModalZone = style({
|
|||
zIndex: 1,
|
||||
});
|
||||
|
||||
export const AuthSplashContent = style({
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
minHeight: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingInline: 'var(--vojo-stack-pad)',
|
||||
boxSizing: 'border-box',
|
||||
});
|
||||
|
||||
/* ── Auth card (glassmorphism) ── */
|
||||
export const AuthCard = style({
|
||||
display: 'flex',
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
MenuItem,
|
||||
PopOut,
|
||||
RectCords,
|
||||
Spinner,
|
||||
Text,
|
||||
} from 'folds';
|
||||
import { HttpApiEvent, HttpApiEventHandlerMap, MatrixClient } from 'matrix-js-sdk';
|
||||
|
|
@ -23,7 +22,6 @@ import {
|
|||
logoutClient,
|
||||
startClient,
|
||||
} from '../../../client/initMatrix';
|
||||
import { SplashScreen } from '../../components/splash-screen';
|
||||
import { ServerConfigsLoader } from '../../components/ServerConfigsLoader';
|
||||
import { CapabilitiesProvider } from '../../hooks/useCapabilities';
|
||||
import { MediaConfigProvider } from '../../hooks/useMediaConfig';
|
||||
|
|
@ -36,16 +34,10 @@ import { SyncStatus } from './SyncStatus';
|
|||
import { AuthMetadataProvider } from '../../hooks/useAuthMetadata';
|
||||
import { getFallbackSession } from '../../state/sessions';
|
||||
import { AutoDiscovery } from './AutoDiscovery';
|
||||
import { AuthSplashScreen } from '../auth/AuthSplashScreen';
|
||||
|
||||
function ClientRootLoading() {
|
||||
return (
|
||||
<SplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Spinner variant="Secondary" size="600" />
|
||||
<Text>Heating up</Text>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
);
|
||||
return <AuthSplashScreen />;
|
||||
}
|
||||
|
||||
function ClientRootOptions({ mx }: { mx?: MatrixClient }) {
|
||||
|
|
@ -189,7 +181,7 @@ export function ClientRoot({ children }: ClientRootProps) {
|
|||
{mx && <SyncStatus mx={mx} />}
|
||||
{loading && <ClientRootOptions mx={mx} />}
|
||||
{(loadState.status === AsyncStatus.Error || startState.status === AsyncStatus.Error) && (
|
||||
<SplashScreen>
|
||||
<AuthSplashScreen>
|
||||
<Box
|
||||
direction="Column"
|
||||
grow="Yes"
|
||||
|
|
@ -213,7 +205,7 @@ export function ClientRoot({ children }: ClientRootProps) {
|
|||
</Box>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
</AuthSplashScreen>
|
||||
)}
|
||||
{loading || !mx ? (
|
||||
<ClientRootLoading />
|
||||
|
|
|
|||
|
|
@ -1,23 +1,16 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
import { Box, Dialog, config, Text, Button, Spinner } from 'folds';
|
||||
import { Box, Dialog, config, Text, Button } from 'folds';
|
||||
import { SpecVersionsLoader } from '../../components/SpecVersionsLoader';
|
||||
import { SpecVersionsProvider } from '../../hooks/useSpecVersions';
|
||||
import { SplashScreen } from '../../components/splash-screen';
|
||||
import { AuthSplashScreen } from '../auth/AuthSplashScreen';
|
||||
|
||||
export function SpecVersions({ baseUrl, children }: { baseUrl: string; children: ReactNode }) {
|
||||
return (
|
||||
<SpecVersionsLoader
|
||||
baseUrl={baseUrl}
|
||||
fallback={() => (
|
||||
<SplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Spinner variant="Secondary" size="600" />
|
||||
<Text>Connecting to server</Text>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
)}
|
||||
fallback={() => <AuthSplashScreen />}
|
||||
error={(err, retry, ignore) => (
|
||||
<SplashScreen>
|
||||
<AuthSplashScreen>
|
||||
<Box direction="Column" grow="Yes" alignItems="Center" justifyContent="Center" gap="400">
|
||||
<Dialog>
|
||||
<Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
|
||||
|
|
@ -37,7 +30,7 @@ export function SpecVersions({ baseUrl, children }: { baseUrl: string; children:
|
|||
</Box>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</SplashScreen>
|
||||
</AuthSplashScreen>
|
||||
)}
|
||||
>
|
||||
{(versions) => <SpecVersionsProvider value={versions}>{children}</SpecVersionsProvider>}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue