feat: auth pages layout (#2042)
* auth pages layout * exclude home route from redirect * fix margin
This commit is contained in:
parent
6683c515cf
commit
975b4dcaab
12 changed files with 124 additions and 61 deletions
|
|
@ -21,6 +21,7 @@ import { useTranslation } from "react-i18next";
|
|||
import JoinedWorkspaces from "@/ee/components/joined-workspaces.tsx";
|
||||
import { useJoinedWorkspacesQuery } from "@/ee/cloud/query/cloud-query.ts";
|
||||
import { findWorkspacesByEmail } from "@/ee/cloud/service/cloud-service.ts";
|
||||
import { AuthLayout } from "@/features/auth/components/auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
hostname: z.string().min(1, { message: "subdomain is required" }),
|
||||
|
|
@ -82,7 +83,7 @@ export function CloudLoginForm() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -145,12 +146,12 @@ export function CloudLoginForm() {
|
|||
</Box>
|
||||
</Container>
|
||||
|
||||
<Text ta="center">
|
||||
<Text ta="center" mb="xl">
|
||||
{t("Don't have a workspace?")}{" "}
|
||||
<Anchor component={Link} to={APP_ROUTE.AUTH.CREATE_WORKSPACE} fw={500}>
|
||||
{t("Create new workspace")}
|
||||
</Anchor>
|
||||
</Text>
|
||||
</div>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import APP_ROUTE, { getPostLoginRedirect } from "@/lib/app-route";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod/v4";
|
||||
import { MfaBackupCodeInput } from "./mfa-backup-code-input";
|
||||
import { AuthLayout } from "@/features/auth/components/auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
code: z
|
||||
|
|
@ -66,6 +67,7 @@ export function MfaChallenge() {
|
|||
};
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Paper radius="lg" p={40} className={classes.paper}>
|
||||
<Stack align="center" gap="xl">
|
||||
|
|
@ -157,5 +159,6 @@ export function MfaChallenge() {
|
|||
</Stack>
|
||||
</Paper>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
|
|||
import { MfaSetupModal } from "@/ee/mfa";
|
||||
import APP_ROUTE, { getPostLoginRedirect } from "@/lib/app-route.ts";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { AuthLayout } from "@/features/auth/components/auth-layout.tsx";
|
||||
|
||||
export default function MfaSetupRequired() {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -15,6 +16,7 @@ export default function MfaSetupRequired() {
|
|||
};
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size="sm" py="xl">
|
||||
<Paper shadow="sm" p="xl" radius="md" withBorder>
|
||||
<Stack>
|
||||
|
|
@ -44,5 +46,6 @@ export default function MfaSetupRequired() {
|
|||
</Stack>
|
||||
</Paper>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
import { notifications } from "@mantine/notifications";
|
||||
import APP_ROUTE from "@/lib/app-route.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AuthLayout } from "@/features/auth/components/auth-layout.tsx";
|
||||
|
||||
export default function VerifyEmail() {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -59,6 +60,7 @@ export default function VerifyEmail() {
|
|||
|
||||
if (token) {
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -69,10 +71,12 @@ export default function VerifyEmail() {
|
|||
</Text>
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -103,5 +107,6 @@ export default function VerifyEmail() {
|
|||
)}
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
26
apps/client/src/features/auth/components/auth-layout.tsx
Normal file
26
apps/client/src/features/auth/components/auth-layout.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import React from "react";
|
||||
import { Group, Text } from "@mantine/core";
|
||||
import classes from "./auth.module.css";
|
||||
|
||||
type AuthLayoutProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function AuthLayout({ children }: AuthLayoutProps) {
|
||||
return (
|
||||
<>
|
||||
<Group justify="center" gap={8} className={classes.logo}>
|
||||
<img
|
||||
src="/icons/favicon-32x32.png"
|
||||
alt="Docmost"
|
||||
width={22}
|
||||
height={22}
|
||||
/>
|
||||
<Text size="28px" fw={700} style={{ userSelect: "none" }}>
|
||||
Docmost
|
||||
</Text>
|
||||
</Group>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,12 +1,20 @@
|
|||
.logo {
|
||||
margin-top: 80px;
|
||||
|
||||
@media (max-width: $mantine-breakpoint-sm) {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 45px 4px;
|
||||
border-radius: 4px;
|
||||
background: light-dark(var(--mantine-color-body), rgba(0, 0, 0, 0.1));
|
||||
margin-top: 150px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@media (max-width: $mantine-breakpoint-sm) {
|
||||
margin-top: 50px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { Box, Button, Container, Text, TextInput, Title } from "@mantine/core";
|
|||
import classes from "./auth.module.css";
|
||||
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AuthLayout } from "./auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z
|
||||
|
|
@ -35,6 +36,7 @@ export function ForgotPasswordForm() {
|
|||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -69,5 +71,6 @@ export function ForgotPasswordForm() {
|
|||
</form>
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { useGetInvitationQuery } from "@/features/workspace/queries/workspace-qu
|
|||
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SsoLogin from "@/ee/components/sso-login.tsx";
|
||||
import { AuthLayout } from "./auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().trim().min(1),
|
||||
|
|
@ -66,6 +67,7 @@ export function InviteSignUpForm() {
|
|||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -111,5 +113,6 @@ export function InviteSignUpForm() {
|
|||
)}
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import SsoLogin from "@/ee/components/sso-login.tsx";
|
|||
import { useWorkspacePublicDataQuery } from "@/features/workspace/queries/workspace-query.ts";
|
||||
import { Error404 } from "@/components/ui/error-404.tsx";
|
||||
import React from "react";
|
||||
import { AuthLayout } from "./auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z
|
||||
|
|
@ -62,6 +63,7 @@ export function LoginForm() {
|
|||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -109,5 +111,6 @@ export function LoginForm() {
|
|||
)}
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Box, Button, Container, PasswordInput, Title } from "@mantine/core";
|
|||
import classes from "./auth.module.css";
|
||||
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AuthLayout } from "./auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
newPassword: z
|
||||
|
|
@ -38,6 +39,7 @@ export function PasswordResetForm({ resetToken }: PasswordResetFormProps) {
|
|||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -59,5 +61,6 @@ export function PasswordResetForm({ resetToken }: PasswordResetFormProps) {
|
|||
</form>
|
||||
</Box>
|
||||
</Container>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import SsoCloudSignup from "@/ee/components/sso-cloud-signup.tsx";
|
|||
import { isCloud } from "@/lib/config.ts";
|
||||
import { Link } from "react-router-dom";
|
||||
import APP_ROUTE from "@/lib/app-route.ts";
|
||||
import { AuthLayout } from "./auth-layout.tsx";
|
||||
|
||||
const formSchema = z.object({
|
||||
workspaceName: z.string().trim().max(50).optional(),
|
||||
|
|
@ -50,7 +51,7 @@ export function SetupWorkspaceForm() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AuthLayout>
|
||||
<Container size={420} className={classes.container}>
|
||||
<Box p="xl" className={classes.containerBox}>
|
||||
<Title order={2} ta="center" fw={500} mb="md">
|
||||
|
|
@ -117,6 +118,6 @@ export function SetupWorkspaceForm() {
|
|||
</Anchor>
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,9 +74,13 @@ function redirectToLogin() {
|
|||
];
|
||||
if (!exemptPaths.some((path) => window.location.pathname.startsWith(path))) {
|
||||
const redirectTo = window.location.pathname;
|
||||
if (redirectTo === APP_ROUTE.HOME) {
|
||||
window.location.href = APP_ROUTE.AUTH.LOGIN;
|
||||
} else {
|
||||
const params = new URLSearchParams({ redirect: redirectTo });
|
||||
window.location.href = `${APP_ROUTE.AUTH.LOGIN}?${params.toString()}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default api;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue