From 975b4dcaab9292a77e8db157d934f18054999e73 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Sun, 22 Mar 2026 16:40:50 +0000
Subject: [PATCH] feat: auth pages layout (#2042)
* auth pages layout
* exclude home route from redirect
* fix margin
---
.../src/ee/components/cloud-login-form.tsx | 7 +-
.../src/ee/mfa/components/mfa-challenge.tsx | 3 +
.../ee/mfa/components/mfa-setup-required.tsx | 3 +
apps/client/src/ee/pages/verify-email.tsx | 25 +++---
.../features/auth/components/auth-layout.tsx | 26 ++++++
.../features/auth/components/auth.module.css | 12 ++-
.../auth/components/forgot-password-form.tsx | 3 +
.../auth/components/invite-sign-up-form.tsx | 3 +
.../features/auth/components/login-form.tsx | 87 ++++++++++---------
.../auth/components/password-reset-form.tsx | 3 +
.../auth/components/setup-workspace-form.tsx | 5 +-
apps/client/src/lib/api-client.ts | 8 +-
12 files changed, 124 insertions(+), 61 deletions(-)
create mode 100644 apps/client/src/features/auth/components/auth-layout.tsx
diff --git a/apps/client/src/ee/components/cloud-login-form.tsx b/apps/client/src/ee/components/cloud-login-form.tsx
index 6ab7ebd9..2357f9bb 100644
--- a/apps/client/src/ee/components/cloud-login-form.tsx
+++ b/apps/client/src/ee/components/cloud-login-form.tsx
@@ -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 (
-
+
@@ -145,12 +146,12 @@ export function CloudLoginForm() {
-
+
{t("Don't have a workspace?")}{" "}
{t("Create new workspace")}
-
+
);
}
diff --git a/apps/client/src/ee/mfa/components/mfa-challenge.tsx b/apps/client/src/ee/mfa/components/mfa-challenge.tsx
index e1d15965..bfa16b22 100644
--- a/apps/client/src/ee/mfa/components/mfa-challenge.tsx
+++ b/apps/client/src/ee/mfa/components/mfa-challenge.tsx
@@ -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 (
+
@@ -157,5 +159,6 @@ export function MfaChallenge() {
+
);
}
diff --git a/apps/client/src/ee/mfa/components/mfa-setup-required.tsx b/apps/client/src/ee/mfa/components/mfa-setup-required.tsx
index ab327c4d..880228a9 100644
--- a/apps/client/src/ee/mfa/components/mfa-setup-required.tsx
+++ b/apps/client/src/ee/mfa/components/mfa-setup-required.tsx
@@ -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 (
+
@@ -44,5 +46,6 @@ export default function MfaSetupRequired() {
+
);
}
diff --git a/apps/client/src/ee/pages/verify-email.tsx b/apps/client/src/ee/pages/verify-email.tsx
index 623c3202..aef5711d 100644
--- a/apps/client/src/ee/pages/verify-email.tsx
+++ b/apps/client/src/ee/pages/verify-email.tsx
@@ -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,20 +60,23 @@ export default function VerifyEmail() {
if (token) {
return (
-
-
-
- {t("Verifying your email")}
-
-
- {t("Please wait...")}
-
-
-
+
+
+
+
+ {t("Verifying your email")}
+
+
+ {t("Please wait...")}
+
+
+
+
);
}
return (
+
@@ -103,5 +107,6 @@ export default function VerifyEmail() {
)}
+
);
}
diff --git a/apps/client/src/features/auth/components/auth-layout.tsx b/apps/client/src/features/auth/components/auth-layout.tsx
new file mode 100644
index 00000000..d05ad7ec
--- /dev/null
+++ b/apps/client/src/features/auth/components/auth-layout.tsx
@@ -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 (
+ <>
+
+
+
+ Docmost
+
+
+ {children}
+ >
+ );
+}
diff --git a/apps/client/src/features/auth/components/auth.module.css b/apps/client/src/features/auth/components/auth.module.css
index 1e7d09d6..9b99200d 100644
--- a/apps/client/src/features/auth/components/auth.module.css
+++ b/apps/client/src/features/auth/components/auth.module.css
@@ -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;
}
}
diff --git a/apps/client/src/features/auth/components/forgot-password-form.tsx b/apps/client/src/features/auth/components/forgot-password-form.tsx
index b5987b49..cdb249c9 100644
--- a/apps/client/src/features/auth/components/forgot-password-form.tsx
+++ b/apps/client/src/features/auth/components/forgot-password-form.tsx
@@ -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 (
+
@@ -69,5 +71,6 @@ export function ForgotPasswordForm() {
+
);
}
diff --git a/apps/client/src/features/auth/components/invite-sign-up-form.tsx b/apps/client/src/features/auth/components/invite-sign-up-form.tsx
index d06ef307..91d8e167 100644
--- a/apps/client/src/features/auth/components/invite-sign-up-form.tsx
+++ b/apps/client/src/features/auth/components/invite-sign-up-form.tsx
@@ -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 (
+
@@ -111,5 +113,6 @@ export function InviteSignUpForm() {
)}
+
);
}
diff --git a/apps/client/src/features/auth/components/login-form.tsx b/apps/client/src/features/auth/components/login-form.tsx
index c07ebe02..78aaa94b 100644
--- a/apps/client/src/features/auth/components/login-form.tsx
+++ b/apps/client/src/features/auth/components/login-form.tsx
@@ -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,52 +63,54 @@ export function LoginForm() {
}
return (
-
-
-
- {t("Login")}
-
+
+
+
+
+ {t("Login")}
+
-
+
- {!data?.enforceSso && (
- <>
-
- >
- )}
-
-
+
+
+ >
+ )}
+
+
+
);
}
diff --git a/apps/client/src/features/auth/components/password-reset-form.tsx b/apps/client/src/features/auth/components/password-reset-form.tsx
index 4fe836ec..d603264f 100644
--- a/apps/client/src/features/auth/components/password-reset-form.tsx
+++ b/apps/client/src/features/auth/components/password-reset-form.tsx
@@ -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 (
+
@@ -59,5 +61,6 @@ export function PasswordResetForm({ resetToken }: PasswordResetFormProps) {
+
);
}
diff --git a/apps/client/src/features/auth/components/setup-workspace-form.tsx b/apps/client/src/features/auth/components/setup-workspace-form.tsx
index 6eaf3d12..8aa55e99 100644
--- a/apps/client/src/features/auth/components/setup-workspace-form.tsx
+++ b/apps/client/src/features/auth/components/setup-workspace-form.tsx
@@ -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 (
-
+
@@ -117,6 +118,6 @@ export function SetupWorkspaceForm() {
)}
-
+
);
}
diff --git a/apps/client/src/lib/api-client.ts b/apps/client/src/lib/api-client.ts
index 632811db..17f7e102 100644
--- a/apps/client/src/lib/api-client.ts
+++ b/apps/client/src/lib/api-client.ts
@@ -74,8 +74,12 @@ function redirectToLogin() {
];
if (!exemptPaths.some((path) => window.location.pathname.startsWith(path))) {
const redirectTo = window.location.pathname;
- const params = new URLSearchParams({ redirect: redirectTo });
- window.location.href = `${APP_ROUTE.AUTH.LOGIN}?${params.toString()}`;
+ 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()}`;
+ }
}
}