diff --git a/packages/app/client/src/pages/document.ejs b/packages/app/client/src/pages/document.ejs
index 349691650..8747521a6 100644
--- a/packages/app/client/src/pages/document.ejs
+++ b/packages/app/client/src/pages/document.ejs
@@ -2,7 +2,7 @@
-
+
Loading...
diff --git a/packages/core/client/src/auth/SigninPage.tsx b/packages/core/client/src/auth/SigninPage.tsx
index 010b1a10e..16e983d22 100644
--- a/packages/core/client/src/auth/SigninPage.tsx
+++ b/packages/core/client/src/auth/SigninPage.tsx
@@ -11,7 +11,7 @@ import React, {
import { css } from '@emotion/css';
import { useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
-import { useAPIClient, useCurrentDocumentTitle, useRequest } from '..';
+import { useAPIClient, useCurrentDocumentTitle, useRequest, useViewport } from '..';
import { useSigninPageExtension } from './SigninPageExtension';
import { useForm } from '@formily/react';
@@ -72,6 +72,7 @@ export const useSignIn = (authenticator) => {
export const SigninPage = () => {
const { t } = useTranslation();
useCurrentDocumentTitle('Signin');
+ useViewport();
const signInPages = useContext(SigninPageContext);
const api = useAPIClient();
const [authenticators, setAuthenticators] = useState([]);
diff --git a/packages/core/client/src/auth/SignupPage.tsx b/packages/core/client/src/auth/SignupPage.tsx
index a62d6bf61..9cf7b8309 100644
--- a/packages/core/client/src/auth/SignupPage.tsx
+++ b/packages/core/client/src/auth/SignupPage.tsx
@@ -2,7 +2,7 @@ import { message } from 'antd';
import React, { useContext, createContext, FunctionComponent, createElement } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
-import { useAPIClient, useCurrentDocumentTitle } from '..';
+import { useAPIClient, useCurrentDocumentTitle, useViewport } from '..';
import { useForm } from '@formily/react';
export const SignupPageContext = createContext<{
@@ -58,6 +58,7 @@ function useQuery() {
export const SignupPage = () => {
const { t } = useTranslation();
+ useViewport();
useCurrentDocumentTitle('Signup');
const query = useQuery();
const authType = query.get('authType');
diff --git a/packages/core/client/src/hooks/index.ts b/packages/core/client/src/hooks/index.ts
new file mode 100644
index 000000000..9319c8453
--- /dev/null
+++ b/packages/core/client/src/hooks/index.ts
@@ -0,0 +1 @@
+export * from './useViewport';
diff --git a/packages/core/client/src/hooks/useViewport.ts b/packages/core/client/src/hooks/useViewport.ts
new file mode 100644
index 000000000..65070c7e7
--- /dev/null
+++ b/packages/core/client/src/hooks/useViewport.ts
@@ -0,0 +1,44 @@
+import { useEffect, useRef } from 'react';
+
+const useViewportMeta = () => {
+ const contentRef = useRef('initial-scale=0.1');
+ const metaRef = useRef();
+
+ useEffect(() => {
+ let meta = document.querySelector('meta[name="viewport"]');
+ if (meta) {
+ contentRef.current = meta.content;
+ } else {
+ meta = document.createElement('meta');
+ meta.name = 'viewport';
+ }
+ if (meta) {
+ meta.content = 'width=device-width, initial-scale=1, user-scalable=0';
+ metaRef.current = meta;
+ }
+ }, []);
+
+ const restore = () => {
+ if (metaRef.current) {
+ metaRef.current.content = contentRef.current;
+ }
+ };
+
+ return {
+ metaRef,
+ restore,
+ };
+};
+
+export function useViewport() {
+ const { metaRef, restore } = useViewportMeta();
+ useEffect(() => {
+ if (!metaRef.current) {
+ return;
+ }
+ document.head.insertBefore(metaRef.current, document.head.firstChild);
+ return () => {
+ restore();
+ };
+ }, []);
+}
diff --git a/packages/core/client/src/index.ts b/packages/core/client/src/index.ts
index d85408281..0cde6613c 100644
--- a/packages/core/client/src/index.ts
+++ b/packages/core/client/src/index.ts
@@ -29,3 +29,4 @@ export * from './schema-items';
export * from './settings-form';
export * from './system-settings';
export * from './user';
+export * from './hooks';
diff --git a/packages/plugins/mobile-client/src/client/router/Application.tsx b/packages/plugins/mobile-client/src/client/router/Application.tsx
index a38a3e954..f3f6f1c41 100644
--- a/packages/plugins/mobile-client/src/client/router/Application.tsx
+++ b/packages/plugins/mobile-client/src/client/router/Application.tsx
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import { useParams } from 'react-router-dom';
-import { ActionContextProvider, AdminProvider, RemoteSchemaComponent, useRoute } from '@nocobase/client';
+import { ActionContextProvider, AdminProvider, RemoteSchemaComponent, useRoute, useViewport } from '@nocobase/client';
import { css, cx } from '@emotion/css';
import { useInterfaceContext } from './InterfaceProvider';
import { DrawerProps, ModalProps } from 'antd';
@@ -73,6 +73,9 @@ const MApplication: React.FC = (props) => {
const Provider = useMemo(() => {
return interfaceContext ? React.Fragment : AdminProvider;
}, [interfaceContext]);
+
+ useViewport();
+
return (