+
+```
+
+### Verification
+
+At this point, the page has been added. Access `http://localhost:5555/home/index` to see the corresponding page.
+
+## Route Configuration
+
+The route configuration mainly resides in the `meta` attribute of the route object. Below are some commonly used configuration items:
+
+```ts {5-8}
+const routes = [
+ {
+ name: 'HomeIndex',
+ path: '/home/index',
+ meta: {
+ icon: 'mdi:home',
+ title: $t('page.home.index'),
+ },
+ },
+];
+```
+
+::: details Route Meta Configuration Type Definition
+
+```ts
+interface RouteMeta {
+ /**
+ * Active icon (menu)
+ */
+ activeIcon?: string;
+ /**
+ * The currently active menu, used when you want to activate a parent menu instead of the existing one
+ * @default false
+ */
+ activePath?: string;
+ /**
+ * Whether to affix the tab
+ * @default false
+ */
+ affixTab?: boolean;
+ /**
+ * The order of the affixed tab
+ * @default 0
+ */
+ affixTabOrder?: number;
+ /**
+ * Specific role identifiers required for access
+ * @default []
+ */
+ authority?: string[];
+ /**
+ * Badge
+ */
+ badge?: string;
+ /**
+ * Badge type
+ */
+ badgeType?: 'dot' | 'normal';
+ /**
+ * Badge color
+ */
+ badgeVariants?:
+ | 'default'
+ | 'destructive'
+ | 'primary'
+ | 'success'
+ | 'warning'
+ | string;
+ /**
+ * Children of the current route do not show in the menu
+ * @default false
+ */
+ hideChildrenInMenu?: boolean;
+ /**
+ * The current route does not show in the breadcrumb
+ * @default false
+ */
+ hideInBreadcrumb?: boolean;
+ /**
+ * The current route does not show in the menu
+ * @default false
+ */
+ hideInMenu?: boolean;
+ /**
+ * The current route does not show in tabs
+ * @default false
+ */
+ hideInTab?: boolean;
+ /**
+ * Icon (menu/tab)
+ */
+ icon?: string;
+ /**
+ * iframe address
+ */
+ iframeSrc?: string;
+ /**
+ * Ignore access, can be accessed directly
+ * @default false
+ */
+ ignoreAccess?: boolean;
+ /**
+ * Enable KeepAlive caching
+ */
+ keepAlive?: boolean;
+ /**
+ * External link - redirect path
+ */
+ link?: string;
+ /**
+ * Whether the route has been loaded
+ */
+ loaded?: boolean;
+ /**
+ * Maximum number of open tabs
+ * @default false
+ */
+ maxNumOfOpenTab?: number;
+ /**
+ * The menu is visible, but access will be redirected to 403
+ */
+ menuVisibleWithForbidden?: boolean;
+ /**
+ * Used for route->menu sorting
+ */
+ order?: number;
+ /**
+ * Title name
+ */
+ title: string;
+}
+```
+
+:::
+
+### title
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the page title, which will be displayed in the menu and tabs. It is generally used in conjunction with internationalization.
+
+### icon
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the page icon, which will be displayed in the menu and tabs. It is generally used in conjunction with an icon library. If it is an `http` link, the image will be automatically loaded.
+
+### activeIcon
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the active icon of the page, which will be displayed in the menu. It is generally used in conjunction with an icon library. If it is an `http` link, the image will be automatically loaded.
+
+### keepAlive
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page caching is enabled. Once enabled, the page will be cached and not reloaded, only effective when tabs are enabled.
+
+### hideInMenu
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page is hidden in the menu. If hidden, the page will not be displayed in the menu.
+
+### hideInTab
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page is hidden in tabs. If hidden, the page will not be displayed in tabs.
+
+### hideInBreadcrumb
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page is hidden in the breadcrumb. If hidden, the page will not be displayed in the breadcrumb.
+
+### hideChildrenInMenu
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the child pages of the page are hidden in the menu. If hidden, the child pages will not be displayed in the menu.
+
+### authority
+
+- Type: `string[]`
+- Default value: `[]`
+
+Used to configure the page's permissions. Only users with corresponding permissions can access the page. If not configured, no permissions are required.
+
+### badge
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the page's badge, which will be displayed in the menu.
+
+### badgeType
+
+- Type: `'dot' | 'normal'`
+- Default value: `'normal'`
+
+Used to configure the type of the page's badge. `dot` is a small red dot, `normal` is text.
+
+### badgeVariants
+
+- Type: `'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`
+- Default value: `'success'`
+
+Used to configure the color of the page's badge.
+
+### activePath
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the currently active menu. Sometimes when the page is not displayed in the menu, it is used to activate the parent menu.
+
+### affixTab
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page tab is pinned. Once pinned, the page cannot be closed.
+
+### affixTabOrder
+
+- Type: `number`
+- Default value: `0`
+
+Used to configure the order of the pinned page tabs, sorted in ascending order.
+
+### iframeSrc
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the `iframe` address of the embedded page. Once set, the corresponding page will be embedded in the current page.
+
+### ignoreAccess
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page ignores permissions and can be accessed directly.
+
+### link
+
+- Type: `string`
+- Default value: `''`
+
+Used to configure the external link jump path, which will be opened in a new window.
+
+### maxNumOfOpenTab
+
+- Type: `number`
+- Default value: `-1`
+
+Used to configure the maximum number of open tabs. Once set, the earliest opened tab will be automatically closed when a new tab is opened (only effective when opening tabs with the same name).
+
+### menuVisibleWithForbidden
+
+- Type: `boolean`
+- Default value: `false`
+
+Used to configure whether the page can be seen in the menu, but access will be redirected to 403.
+
+### order
+
+- Type: `number`
+- Default value: `0`
+
+Used to configure the page's order, for routing to menu sorting.
+
+## Route Refresh
+
+The way to refresh the route is as follows:
+
+```vue
+
+```
diff --git a/docs/src/en/guide/essentials/server.md b/docs/src/en/guide/essentials/server.md
new file mode 100644
index 00000000..53ce1e43
--- /dev/null
+++ b/docs/src/en/guide/essentials/server.md
@@ -0,0 +1,347 @@
+# Server Interaction and Data Mocking
+
+::: tip Note
+
+This document explains how to use Mock data and interact with the server in a development environment, involving technologies such as:
+
+- [Nitro](https://nitro.unjs.io/) A lightweight backend server that can be deployed anywhere, used as a Mock server in the project.
+- [axios](https://axios-http.com/docs/intro) Used to send HTTP requests to interact with the server.
+
+:::
+
+## Interaction in Development Environment
+
+If the frontend application and the backend API server are not running on the same host, you need to proxy the API requests to the API server in the development environment. If they are on the same host, you can directly request the specific API endpoint.
+
+### Local Development CORS Configuration
+
+::: tip Hint
+
+The CORS configuration for local development has already been set up. If you have other requirements, you can add or adjust the configuration as needed.
+
+:::
+
+#### Configuring Local Development API Endpoint
+
+Configure the API endpoint in the `.env.development` file at the project root directory, here it is set to `/api`:
+
+```bash
+VITE_GLOB_API_URL=/api
+```
+
+#### Configuring Development Server Proxy
+
+In the development environment, if you need to handle CORS, configure the API endpoint in the `vite.config.mts` file under the corresponding application directory:
+
+```ts{8-16}
+// apps/web-antd/vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+ return {
+ vite: {
+ server: {
+ proxy: {// [!code focus:11]
+ '/api': {
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/api/, ''),
+ // mock proxy
+ target: 'http://localhost:5320/api',
+ ws: true,
+ },
+ },
+ },
+ },
+ };
+});
+```
+
+#### API Requests
+
+Based on the above configuration, we can use `/api` as the prefix for API requests in our frontend project, for example:
+
+```ts
+import axios from 'axios';
+
+axios.get('/api/user').then((res) => {
+ console.log(res);
+});
+```
+
+At this point, the request will be proxied to `http://localhost:5320/api/user`.
+
+::: warning Note
+
+From the browser's console Network tab, the request appears as `http://localhost:5555/api/user`. This is because the proxy configuration does not change the local request's URL.
+
+:::
+
+### Configuration Without CORS
+
+If there is no CORS issue, you can directly ignore the [Configure Development Server Proxy](./server.md#configure-development-server-proxy) settings and set the API endpoint directly in `VITE_GLOB_API_URL`.
+
+Configure the API endpoint in the `.env.development` file at the project root directory:
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+## Production Environment Interaction
+
+### API Endpoint Configuration
+
+Configure the API endpoint in the `.env.production` file at the project root directory:
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+::: tip How to Dynamically Modify API Endpoint in Production
+
+Variables starting with `VITE_GLOB_*` in the `.env` file are injected into the `_app.config.js` file during packaging. After packaging, you can modify the corresponding API addresses in `dist/_app.config.js` and refresh the page to apply the changes. This eliminates the need to package multiple times for different environments, allowing a single package to be deployed across multiple API environments.
+
+:::
+
+### Cross-Origin Resource Sharing (CORS) Handling
+
+In the production environment, if CORS issues arise, you can use `nginx` to proxy the API address or enable `cors` on the backend to handle it (refer to the mock service for examples).
+
+## API Request Configuration
+
+The project comes with a default basic request configuration based on `axios`, provided by the `@vben/request` package. The project does not overly complicate things but simply wraps some common configurations. If there are other requirements, you can add or adjust the configurations as needed. Depending on the app, different component libraries and `store` might be used, so under the `src/api/request.ts` folder in the application directory, there are corresponding request configuration files. For example, in the `web-antd` project, there's a `src/api/request.ts` file where you can configure according to your needs.
+
+### Request Examples
+
+#### GET Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function getUserInfoApi() {
+ return requestClient.get('/user/info');
+}
+```
+
+#### POST/PUT Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function saveUserApi(user: UserInfo) {
+ return requestClient.post('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+ return requestClient.put('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+ const url = user.id ? `/user/${user.id}` : '/user/';
+ return requestClient.request(url, {
+ data: user,
+ // OR PUT
+ method: user.id ? 'PUT' : 'POST',
+ });
+}
+```
+
+#### DELETE Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function deleteUserApi(user: UserInfo) {
+ return requestClient.delete(`/user/${user.id}`, user);
+}
+```
+
+### Request Configuration
+
+The `src/api/request.ts` within the application can be configured according to the needs of your application:
+
+```ts
+/**
+ * This file can be adjusted according to business logic
+ */
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+ authenticateResponseInterceptor,
+ errorMessageResponseInterceptor,
+ RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+ const client = new RequestClient({
+ baseURL,
+ });
+
+ /**
+ * Re-authentication Logic
+ */
+ async function doReAuthenticate() {
+ console.warn('Access token or refresh token is invalid or expired. ');
+ const accessStore = useAccessStore();
+ const authStore = useAuthStore();
+ accessStore.setAccessToken(null);
+ if (preferences.app.loginExpiredMode === 'modal') {
+ accessStore.setLoginExpired(true);
+ } else {
+ await authStore.logout();
+ }
+ }
+
+ /**
+ * Refresh token Logic
+ */
+ async function doRefreshToken() {
+ const accessStore = useAccessStore();
+ const resp = await refreshTokenApi();
+ const newToken = resp.data;
+ accessStore.setAccessToken(newToken);
+ return newToken;
+ }
+
+ function formatToken(token: null | string) {
+ return token ? `Bearer ${token}` : null;
+ }
+
+ // Request Header Processing
+ client.addRequestInterceptor({
+ fulfilled: async (config) => {
+ const accessStore = useAccessStore();
+
+ config.headers.Authorization = formatToken(accessStore.accessToken);
+ config.headers['Accept-Language'] = preferences.app.locale;
+ return config;
+ },
+ });
+
+ // Deal Response Data
+ client.addResponseInterceptor({
+ fulfilled: (response) => {
+ const { data: responseData, status } = response;
+
+ const { code, data, message: msg } = responseData;
+
+ if (status >= 200 && status < 400 && code === 0) {
+ return data;
+ }
+ throw new Error(`Error ${status}: ${msg}`);
+ },
+ });
+
+ // Handling Token Expiration
+ client.addResponseInterceptor(
+ authenticateResponseInterceptor({
+ client,
+ doReAuthenticate,
+ doRefreshToken,
+ enableRefreshToken: preferences.app.enableRefreshToken,
+ formatToken,
+ }),
+ );
+
+ // Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
+ client.addResponseInterceptor(
+ errorMessageResponseInterceptor((msg: string) => message.error(msg)),
+ );
+
+ return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
+```
+
+### Multiple API Endpoints
+
+To handle multiple API endpoints, simply create multiple `requestClient` instances, as follows:
+
+```ts
+const { apiURL, otherApiURL } = useAppConfig(
+ import.meta.env,
+ import.meta.env.PROD,
+);
+
+export const requestClient = createRequestClient(apiURL);
+
+export const otherRequestClient = createRequestClient(otherApiURL);
+```
+
+## Refresh Token
+
+The project provides a default logic for refreshing tokens. To enable it, follow the configuration below:
+
+- Ensure the refresh token feature is enabled
+
+Adjust the `preferences.ts` in the corresponding application directory to ensure `enableRefreshToken='true'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ enableRefreshToken: true,
+ },
+});
+```
+
+Configure the `doRefreshToken` method in `src/api/request.ts` as follows:
+
+```ts
+// Adjust this to your token format
+function formatToken(token: null | string) {
+ return token ? `Bearer ${token}` : null;
+}
+
+/**
+ * Refresh token logic
+ */
+async function doRefreshToken() {
+ const accessStore = useAccessStore();
+ // Adjust this to your refresh token API
+ const resp = await refreshTokenApi();
+ const newToken = resp.data;
+ accessStore.setAccessToken(newToken);
+ return newToken;
+}
+```
+
+## Data Mocking
+
+::: tip Production Environment Mock
+
+The new version no longer supports mock in the production environment. Please use real interfaces.
+
+:::
+
+Mock data is an indispensable part of frontend development, serving as a key link in separating frontend and backend development. By agreeing on interfaces with the server side in advance and simulating request data and even logic, frontend development can proceed independently, without being blocked by the backend development process.
+
+The project uses [Nitro](https://nitro.unjs.io/) for local mock data processing. The principle is to start an additional backend service locally, which is a real backend service that can handle requests and return data.
+
+### Using Nitro
+
+The mock service code is located in the `apps/backend-mock` directory. It does not need to be started manually and is already integrated into the project. You only need to run `pnpm dev` in the project root directory. After running successfully, the console will print `http://localhost:5320/api`, and you can access this address to view the mock service.
+
+[Nitro](https://nitro.unjs.io/) syntax is simple, and you can configure and develop according to your needs. For specific configurations, you can refer to the [Nitro documentation](https://nitro.unjs.io/).
+
+## Disabling Mock Service
+
+Since mock is essentially a real backend service, if you do not need the mock service, you can configure `VITE_NITRO_MOCK=false` in the `.env.development` file in the project root directory to disable the mock service.
+
+```bash
+# .env.development
+VITE_NITRO_MOCK=false
+```
diff --git a/docs/src/en/guide/essentials/settings.md b/docs/src/en/guide/essentials/settings.md
new file mode 100644
index 00000000..719b1d91
--- /dev/null
+++ b/docs/src/en/guide/essentials/settings.md
@@ -0,0 +1,511 @@
+# Configuration
+
+## Environment Variable Configuration
+
+The project's environment variable configuration is located in the application directory under `.env`, `.env.development`, `.env.production`.
+
+The rules are consistent with [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html). The format is as follows:
+
+```bash
+.env # Loaded in all environments
+.env.local # Loaded in all environments, but ignored by git
+.env.[mode] # Only loaded in the specified mode
+.env.[mode].local # Only loaded in the specified mode, but ignored by git
+```
+
+::: tip
+
+- Only variables starting with `VITE_` will be embedded into the client-side package. You can access them in the project code like this:
+
+ ```ts
+ console.log(import.meta.env.VITE_PROT);
+ ```
+
+- Variables starting with `VITE_GLOB_*` will be added to the `_app.config.js` configuration file during packaging. :::
+
+:::
+
+## Environment Configuration Description
+
+::: code-group
+
+```bash [.env]
+# Application title
+VITE_APP_TITLE=Vben Admin
+
+# Application namespace, used as a prefix for caching, store, etc., to ensure isolation
+VITE_APP_NAMESPACE=vben-web-antd
+```
+
+```bash [.env.development]
+# Port Number
+VITE_PORT=5555
+
+# Public Path for Resources, must start and end with /
+VITE_BASE=/
+
+# API URL
+VITE_GLOB_API_URL=/api
+
+# Whether to enable Nitro Mock service, true to enable, false to disable
+VITE_NITRO_MOCK=true
+
+# Whether to open devtools, true to open, false to close
+VITE_DEVTOOLS=true
+
+# Whether to inject global loading
+VITE_INJECT_APP_LOADING=true
+```
+
+:::
+
+## Dynamic Configuration in Production Environment
+
+When executing `pnpm build` in the root directory of the monorepo, a `dist/_app.config.js` file will be automatically generated in the corresponding application and inserted into `index.html`.
+
+`_app.config.js` is a dynamic configuration file that allows for modifications to the configuration dynamically based on different environments after the project has been built. The content is as follows:
+
+```ts
+window._VBEN_ADMIN_PRO_APP_CONF_ = {
+ VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',
+};
+Object.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);
+Object.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {
+ configurable: false,
+ writable: false,
+});
+```
+
+### Purpose
+
+`_app.config.js` is used for projects that need to dynamically modify configurations after packaging, such as API endpoints. There's no need to repackage; you can simply modify the variables in `/dist/_app.config.js` after packaging, and refresh to update the variables in the code. A `js` file is used to ensure that the configuration file is loaded early in the order.
+
+### Usage
+
+To access the variables inside `_app.config.js`, you need to use the `useAppConfig` method provided by `@vben/hooks`.
+
+```ts
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+### Adding New
+
+To add a new dynamically modifiable configuration item, simply follow the steps below:
+
+- First, add the variable that needs to be dynamically configurable in the `.env` file or the corresponding development environment configuration file. The variable must start with `VITE_GLOB_*`, for example:
+
+ ```bash
+ VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api
+ ```
+
+- In `packages/types/global.d.ts`, add the corresponding type definition, such as:
+
+ ```ts
+ export interface VbenAdminProAppConfigRaw {
+ VITE_GLOB_API_URL: string;
+ VITE_GLOB_OTHER_API_URL: string; // [!code ++]
+ }
+
+ export interface ApplicationConfig {
+ apiURL: string;
+ otherApiURL: string; // [!code ++]
+ }
+ ```
+
+At this point, you can use the `useAppConfig` method within the project to access the newly added configuration item.
+
+```ts
+const { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+::: warning Warning
+
+The `useAppConfig` method should only be used within the application and not be coupled with the internals of a package. The reason for passing `import.meta.env` and `import.meta.env.PROD` is to avoid such coupling. A pure package should avoid using variables specific to a particular build tool.
+
+:::
+
+## Preferences
+
+The project offers a wide range of preference settings for dynamically configuring various features of the project:
+
+![](/guide/preferences.png)
+
+If you cannot find documentation for a setting, you can try configuring it yourself and then click `Copy Preferences` to override the project defaults. The configuration file is located in the application directory under `preferences.ts`, where you can override the framework's default configurations to achieve custom settings.
+
+```ts
+import { useAppConfig } from '@vben/hooks';
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description Project configuration file
+ * Only a part of the configuration in the project needs to be covered, and unnecessary configurations do not need to be covered. The default configuration will be automatically used
+ */
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+});
+```
+
+### Framework default configuration
+
+::: details View the default configuration of the framework
+
+```ts
+const defaultPreferences: Preferences = {
+ app: {
+ accessMode: 'frontend',
+ authPageLayout: 'panel-right',
+ checkUpdatesInterval: 1,
+ colorGrayMode: false,
+ colorWeakMode: false,
+ compact: false,
+ contentCompact: 'wide',
+ defaultAvatar:
+ 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/avatar-v1.webp',
+ dynamicTitle: true,
+ enableCheckUpdates: true,
+ enablePreferences: true,
+ enableRefreshToken: false,
+ isMobile: false,
+ layout: 'sidebar-nav',
+ locale: 'zh-CN',
+ loginExpiredMode: 'modal',
+ name: 'Vben Admin',
+ preferencesButtonPosition: 'fixed',
+ watermark: false,
+ },
+ breadcrumb: {
+ enable: true,
+ hideOnlyOne: false,
+ showHome: false,
+ showIcon: true,
+ styleType: 'normal',
+ },
+ copyright: {
+ companyName: 'Vben',
+ companySiteLink: 'https://www.vben.pro',
+ date: '2024',
+ enable: true,
+ icp: '',
+ icpLink: '',
+ },
+ footer: {
+ enable: true,
+ fixed: false,
+ },
+ header: {
+ enable: true,
+ hidden: false,
+ mode: 'fixed',
+ },
+ logo: {
+ enable: true,
+ source: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp',
+ },
+ navigation: {
+ accordion: true,
+ split: true,
+ styleType: 'rounded',
+ },
+ shortcutKeys: {
+ enable: true,
+ globalLockScreen: true,
+ globalLogout: true,
+ globalPreferences: true,
+ globalSearch: true,
+ },
+ sidebar: {
+ collapsed: false,
+ collapsedShowTitle: false,
+ enable: true,
+ expandOnHover: true,
+ extraCollapse: true,
+ hidden: false,
+ width: 230,
+ },
+ tabbar: {
+ dragable: true,
+ enable: true,
+ height: 36,
+ keepAlive: true,
+ persist: true,
+ showIcon: true,
+ showMaximize: true,
+ showMore: true,
+ showRefresh: true,
+ styleType: 'chrome',
+ },
+ theme: {
+ builtinType: 'default',
+ colorDestructive: 'hsl(348 100% 61%)',
+ colorPrimary: 'hsl(231 98% 65%)',
+ colorSuccess: 'hsl(144 57% 58%)',
+ colorWarning: 'hsl(42 84% 61%)',
+ mode: 'dark',
+ radius: '0.5',
+ semiDarkHeader: false,
+ semiDarkSidebar: true,
+ },
+ transition: {
+ enable: true,
+ loading: true,
+ name: 'fade-slide',
+ progress: true,
+ },
+ widget: {
+ fullscreen: true,
+ globalSearch: true,
+ languageToggle: true,
+ lockScreen: true,
+ notification: true,
+ sidebarToggle: true,
+ themeToggle: true,
+ },
+};
+```
+
+:::
+
+::: details View the default configuration type of the framework
+
+```ts
+interface AppPreferences {
+ /** Permission mode */
+ accessMode: AccessModeType;
+ /** Layout of the login/registration page */
+ authPageLayout: AuthPageLayoutType;
+ /** Interval for checking updates */
+ checkUpdatesInterval: number;
+ /** Whether to enable gray mode */
+ colorGrayMode: boolean;
+ /** Whether to enable color weakness mode */
+ colorWeakMode: boolean;
+ /** Whether to enable compact mode */
+ compact: boolean;
+ /** Whether to enable content compact mode */
+ contentCompact: ContentCompactType;
+ // /** Default application avatar */
+ defaultAvatar: string;
+ // /** Enable dynamic title */
+ dynamicTitle: boolean;
+ /** Whether to enable update checks */
+ enableCheckUpdates: boolean;
+ /** Whether to display preferences */
+ enablePreferences: boolean;
+ /**
+ * @zh_CN Whether to enable refreshToken
+ */
+ enableRefreshToken: boolean;
+ /** Whether it's mobile */
+ isMobile: boolean;
+ /** Layout method */
+ layout: LayoutType;
+ /** Supported languages */
+ locale: SupportedLanguagesType;
+ /** Login expiration mode */
+ loginExpiredMode: LoginExpiredModeType;
+ /** Application name */
+ name: string;
+ /** Position of the preferences button */
+ preferencesButtonPosition: PreferencesButtonPositionType;
+ /**
+ * @zh_CN Whether to enable watermark
+ */
+ watermark: boolean;
+}
+interface BreadcrumbPreferences {
+ /** Whether breadcrumbs are enabled */
+ enable: boolean;
+ /** Whether to hide breadcrumbs when there is only one */
+ hideOnlyOne: boolean;
+ /** Whether the home icon in breadcrumbs is visible */
+ showHome: boolean;
+ /** Whether the icon in breadcrumbs is visible */
+ showIcon: boolean;
+ /** Breadcrumb style */
+ styleType: BreadcrumbStyleType;
+}
+
+interface CopyrightPreferences {
+ /** Copyright company name */
+ companyName: string;
+ /** Link to the copyright company's site */
+ companySiteLink: string;
+ /** Copyright date */
+ date: string;
+ /** Whether copyright is visible */
+ enable: boolean;
+ /** ICP number */
+ icp: string;
+ /** Link to the ICP */
+ icpLink: string;
+}
+
+interface FooterPreferences {
+ /** Whether the footer is visible */
+ enable: boolean;
+ /** Whether the footer is fixed */
+ fixed: boolean;
+}
+
+interface HeaderPreferences {
+ /** Whether the header is enabled */
+ enable: boolean;
+ /** Whether the header is hidden, css-hidden */
+ hidden: boolean;
+ /** Header display mode */
+ mode: LayoutHeaderModeType;
+}
+
+interface LogoPreferences {
+ /** Whether the logo is visible */
+ enable: boolean;
+ /** Logo URL */
+ source: string;
+}
+
+interface NavigationPreferences {
+ /** Navigation menu accordion mode */
+ accordion: boolean;
+ /** Whether the navigation menu is split, only effective in layout=mixed-nav */
+ split: boolean;
+ /** Navigation menu style */
+ styleType: NavigationStyleType;
+}
+interface SidebarPreferences {
+ /** Whether the sidebar is collapsed */
+ collapsed: boolean;
+ /** Whether to show title when sidebar is collapsed */
+ collapsedShowTitle: boolean;
+ /** Whether the sidebar is visible */
+ enable: boolean;
+ /** Menu auto-expand state */
+ expandOnHover: boolean;
+ /** Whether the sidebar extension area is collapsed */
+ extraCollapse: boolean;
+ /** Whether the sidebar is hidden - css */
+ hidden: boolean;
+ /** Sidebar width */
+ width: number;
+}
+
+interface ShortcutKeyPreferences {
+ /** Whether shortcut keys are enabled globally */
+ enable: boolean;
+ /** Whether the global lock screen shortcut is enabled */
+ globalLockScreen: boolean;
+ /** Whether the global logout shortcut is enabled */
+ globalLogout: boolean;
+ /** Whether the global preferences shortcut is enabled */
+ globalPreferences: boolean;
+ /** Whether the global search shortcut is enabled */
+ globalSearch: boolean;
+}
+
+interface TabbarPreferences {
+ /** Whether dragging of multiple tabs is enabled */
+ dragable: boolean;
+ /** Whether multiple tabs are enabled */
+ enable: boolean;
+ /** Tab height */
+ height: number;
+ /** Whether tab caching is enabled */
+ keepAlive: boolean;
+ /** Whether tabs are persistent */
+ persist: boolean;
+ /** Whether icons in multiple tabs are enabled */
+ showIcon: boolean;
+ /** Whether to show the maximize button */
+ showMaximize: boolean;
+ /** Whether to show the more button */
+ showMore: boolean;
+ /** Whether to show the refresh button */
+ showRefresh: boolean;
+ /** Tab style */
+ styleType: TabsStyleType;
+}
+interface ThemePreferences {
+ /** Built-in theme name */
+ builtinType: BuiltinThemeType;
+ /** Destructive color */
+ colorDestructive: string;
+ /** Primary color */
+ colorPrimary: string;
+ /** Success color */
+ colorSuccess: string;
+ /** Warning color */
+ colorWarning: string;
+ /** Current theme */
+ mode: ThemeModeType;
+ /** Radius */
+ radius: string;
+ /** Whether to enable semi-dark header (only effective when theme='light') */
+ semiDarkHeader: boolean;
+ /** Whether to enable semi-dark sidebar (only effective when theme='light') */
+ semiDarkSidebar: boolean;
+}
+
+interface TransitionPreferences {
+ /** Whether page transition animations are enabled */
+ enable: boolean;
+ // /** Whether page loading loading is enabled */
+ loading: boolean;
+ /** Page transition animation */
+ name: PageTransitionType | string;
+ /** Whether page loading progress animation is enabled */
+ progress: boolean;
+}
+
+interface WidgetPreferences {
+ /** Whether fullscreen widgets are enabled */
+ fullscreen: boolean;
+ /** Whether global search widget is enabled */
+ globalSearch: boolean;
+ /** Whether language switch widget is enabled */
+ languageToggle: boolean;
+ /** Whether lock screen functionality is enabled */
+ lockScreen: boolean;
+ /** Whether notification widget is displayed */
+ notification: boolean;
+ /** Whether sidebar show/hide widget is displayed */
+ sidebarToggle: boolean;
+ /** Whether theme switch widget is displayed */
+ themeToggle: boolean;
+}
+interface Preferences {
+ /** Global configuration */
+ app: AppPreferences;
+ /** Header configuration */
+ breadcrumb: BreadcrumbPreferences;
+ /** Copyright configuration */
+ copyright: CopyrightPreferences;
+ /** Footer configuration */
+ footer: FooterPreferences;
+ /** Breadcrumb configuration */
+ header: HeaderPreferences;
+ /** Logo configuration */
+ logo: LogoPreferences;
+ /** Navigation configuration */
+ navigation: NavigationPreferences;
+ /** Shortcut key configuration */
+ shortcutKeys: ShortcutKeyPreferences;
+ /** Sidebar configuration */
+ sidebar: SidebarPreferences;
+ /** Tab bar configuration */
+ tabbar: TabbarPreferences;
+ /** Theme configuration */
+ theme: ThemePreferences;
+ /** Animation configuration */
+ transition: TransitionPreferences;
+ /** Widget configuration */
+ widget: WidgetPreferences;
+}
+```
+
+:::
+
+::: warning Warning
+
+- The `overridesPreferences` method only needs to override a part of the configurations in the project. There's no need to override configurations that are not needed; they will automatically use the default settings.
+- Any configuration item can be overridden. You just need to override it within the `overridesPreferences` method. Do not modify the default configuration file.
+
+:::
diff --git a/docs/src/en/guide/essentials/styles.md b/docs/src/en/guide/essentials/styles.md
new file mode 100644
index 00000000..90290081
--- /dev/null
+++ b/docs/src/en/guide/essentials/styles.md
@@ -0,0 +1,106 @@
+# Styles
+
+::: tip Preface
+
+For Vue projects, the [official documentation](https://vuejs.org/api/sfc-css-features.html#deep-selectors) already provides a detailed introduction to the syntax. Here, we mainly introduce the structure and usage of style files in the project.
+
+:::
+
+## Project Structure
+
+The style files in the project are stored in `@vben/styles`, which includes some global styles, such as reset styles, global variables, etc. It inherits the styles and capabilities of `@vben-core/design` and can be overridden according to project needs.
+
+## Scss
+
+The project uses `scss` as the style preprocessor, allowing the use of `scss` features such as variables, functions, mixins, etc., within the project.
+
+```vue
+
+```
+
+## Postcss
+
+If you're not accustomed to using `scss`, you can also use `postcss`, which is a more powerful style processor that supports a wider range of plugins. The project includes the [postcss-nested](https://github.com/postcss/postcss-nested) plugin and is configured with `Css Variables`, making it a complete substitute for `scss`.
+
+```vue
+
+```
+
+## Tailwind CSS
+
+The project integrates [Tailwind CSS](https://tailwindcss.com/), allowing the use of `tailwindcss` class names to quickly build pages.
+
+```vue
+
+
+
hello world
+
+
+```
+
+## BEM Standard
+
+Another option to avoid style conflicts is to use the `BEM` standard. If you choose `scss`, it is recommended to use the `BEM` naming convention for better style management. The project provides a default `useNamespace` function to easily generate namespaces.
+
+```vue
+
+
+
+
item1
+
+
+
+```
+
+## CSS Modules
+
+Another solution to address style conflicts is to use the `CSS Modules` modular approach. The usage method is as follows.
+
+```vue
+
+
This should be red
+
+
+
+```
+
+For more usage, see the [CSS Modules official documentation](https://vuejs.org/api/sfc-css-features.html#css-modules).
diff --git a/docs/src/en/guide/in-depth/access.md b/docs/src/en/guide/in-depth/access.md
new file mode 100644
index 00000000..fd06fa28
--- /dev/null
+++ b/docs/src/en/guide/in-depth/access.md
@@ -0,0 +1,314 @@
+---
+outline: deep
+---
+
+# Access Control
+
+The framework has built-in two types of access control methods:
+
+- Determining whether a menu or button can be accessed based on user roles
+- Determining whether a menu or button can be accessed through an API
+
+## Frontend Access Control
+
+**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoutes`, achieving permission filtering.
+
+**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
+
+### Steps
+
+- Ensure the current mode is set to frontend access control
+
+Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ // Default value, optional
+ accessMode: 'frontend',
+ },
+});
+```
+
+- Configure route permissions
+
+#### If not configured, it is visible by default
+
+```ts {3}
+ {
+ meta: {
+ authority: ['super'],
+ },
+},
+```
+
+- Ensure the roles returned by the interface match the permissions in the route table
+
+You can look under `src/store/auth` in the application to find the following code:
+
+```ts
+// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table
+// For example: userInfo.roles=['super', 'admin']
+authStore.setUserInfo(userInfo);
+```
+
+At this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.
+
+### Menu Visible but Access Forbidden
+
+Sometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.
+
+```ts
+{
+ meta: {
+ menuVisibleWithForbidden: true,
+ },
+},
+```
+
+## Backend Access Control
+
+**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoutes`, realizing the dynamic generation of permissions.
+
+**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
+
+### Steps
+
+- Ensure the current mode is set to backend access control
+
+Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ accessMode: 'backend',
+ },
+});
+```
+
+- Ensure the structure of the menu data returned by the interface is correct
+
+You can look under `src/router/access.ts` in the application to find the following code:
+
+```ts
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+ return await generateAccessible(preferences.app.accessMode, {
+ fetchMenuListAsync: async () => {
+ // This interface is for the menu data returned by the backend
+ return await getAllMenus();
+ },
+ });
+}
+```
+
+- Interface returns menu data, see comments for explanation
+
+::: details Example of Interface Returning Menu Data
+
+```ts
+const dashboardMenus = [
+ {
+ // Here, 'BasicLayout' is hardcoded and cannot be changed
+ component: 'BasicLayout',
+ meta: {
+ order: -1,
+ title: 'page.dashboard.title',
+ },
+ name: 'Dashboard',
+ path: '/',
+ redirect: '/analytics',
+ children: [
+ {
+ name: 'Analytics',
+ path: '/analytics',
+ // Here is the path of the page, need to remove 'views/' and '.vue'
+ component: '/dashboard/analytics/index',
+ meta: {
+ affixTab: true,
+ title: 'page.dashboard.analytics',
+ },
+ },
+ {
+ name: 'Workspace',
+ path: '/workspace',
+ component: '/dashboard/workspace/index',
+ meta: {
+ title: 'page.dashboard.workspace',
+ },
+ },
+ ],
+ },
+];
+```
+
+:::
+
+At this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.
+
+## Fine-grained Control of Buttons
+
+In some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.
+
+### Permission Code
+
+The permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:
+
+```ts
+const [fetchUserInfoResult, accessCodes] = await Promise.all([
+ fetchUserInfo(),
+ getAccessCodes(),
+]);
+
+userInfo = fetchUserInfoResult;
+authStore.setUserInfo(userInfo);
+accessStore.setAccessCodes(accessCodes);
+```
+
+Locate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.
+
+The data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
+
+With the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.
+
+#### Component Method
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+#### API Method
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+#### Directive Method
+
+```vue
+
+
+
+
+
+
+```
+
+### Roles
+
+The method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.
+
+#### Component Method
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+#### API Method
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+#### Directive Method
+
+```vue
+
+
+
+
+
+
+```
diff --git a/docs/src/en/guide/in-depth/check-updates.md b/docs/src/en/guide/in-depth/check-updates.md
new file mode 100644
index 00000000..1e5b679d
--- /dev/null
+++ b/docs/src/en/guide/in-depth/check-updates.md
@@ -0,0 +1,48 @@
+# Check Updates
+
+## Introduction
+
+When there are updates to the website, you might need to check for updates. The framework provides this functionality. By periodically checking for updates, you can configure the `checkUpdatesInterval` and `enableCheckUpdates` fields in your application's preferences.ts file to enable and set the interval for checking updates (in minutes).
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ // Whether to enable check for updates
+ enableCheckUpdates: true,
+ // The interval for checking updates, in minutes
+ checkUpdatesInterval: 1,
+ },
+});
+```
+
+## Effect
+
+When an update is detected, a prompt will pop up asking the user whether to refresh the page:
+
+![check-updates](/guide/update-notice.png)
+
+## Replacing with Other Update Checking Methods
+
+If you need to check for updates in other ways, such as through an API to more flexibly control the update logic (such as force refresh, display update content, etc.), you can do so by modifying the `src/widgets/check-updates/check-updates.vue` file under `@vben/layouts`.
+
+```ts
+// Replace this with your update checking logic
+async function getVersionTag() {
+ try {
+ const response = await fetch('/', {
+ cache: 'no-cache',
+ method: 'HEAD',
+ });
+
+ return (
+ response.headers.get('etag') || response.headers.get('last-modified')
+ );
+ } catch {
+ console.error('Failed to fetch version tag');
+ return null;
+ }
+}
+```
diff --git a/docs/src/en/guide/in-depth/features.md b/docs/src/en/guide/in-depth/features.md
new file mode 100644
index 00000000..8a459950
--- /dev/null
+++ b/docs/src/en/guide/in-depth/features.md
@@ -0,0 +1,84 @@
+# Common Features
+
+A collection of some commonly used features.
+
+## Login Authentication Expiry
+
+When the interface returns a `401` status code, the framework will consider the login authentication to have expired. Upon login timeout, it will redirect to the login page or open a login popup. This can be configured in `preferences.ts` in the application directory:
+
+### Redirect to Login Page
+
+Upon login timeout, it will redirect to the login page.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ loginExpiredMode: 'page',
+ },
+});
+```
+
+### Open Login Popup
+
+When login times out, a login popup will open.
+
+![login-expired](/guide/login-expired.png)
+
+Configuration:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ loginExpiredMode: 'model',
+ },
+});
+```
+
+## Dynamic Title
+
+- Default value: `true`
+
+When enabled, the webpage title changes according to the route's `title`. You can enable or disable this in the `preferences.ts` file in your application directory.
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ dynamicTitle: true,
+ },
+});
+```
+
+## Page Watermark
+
+- Default value: `false`
+
+When enabled, the webpage will display a watermark. You can enable or disable this in the `preferences.ts` file in your application directory.
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+ // overrides
+ app: {
+ watermark: true,
+ },
+});
+```
+
+If you want to update the content of the watermark, you can do so. The parameters can be referred to [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):
+
+```ts
+import { useWatermark } from '@vben/hooks';
+
+const { destroyWatermark, updateWatermark } = useWatermark();
+
+await updateWatermark({
+ // watermark content
+ content: 'hello my watermark',
+});
+```
diff --git a/docs/src/en/guide/in-depth/layout.md b/docs/src/en/guide/in-depth/layout.md
new file mode 100644
index 00000000..412c1cf0
--- /dev/null
+++ b/docs/src/en/guide/in-depth/layout.md
@@ -0,0 +1 @@
+# Layout
diff --git a/docs/src/en/guide/in-depth/loading.md b/docs/src/en/guide/in-depth/loading.md
new file mode 100644
index 00000000..0f1cff6e
--- /dev/null
+++ b/docs/src/en/guide/in-depth/loading.md
@@ -0,0 +1,44 @@
+# Global Loading
+
+Global loading refers to the loading effect that appears when the page is refreshed, usually a spinning icon:
+
+![Global loading spinner](/guide/loading.png)
+
+## Principle
+
+Implemented by the `vite-plugin-inject-app-loading` plugin, the plugin injects a global `loading html` into each application.
+
+## Disable
+
+If you do not need global loading, you can disable it in the `.env` file:
+
+```bash
+VITE_INJECT_APP_LOADING=false
+```
+
+## Customization
+
+If you want to customize the global loading, you can create a `loading.html` file in the application directory, at the same level as `index.html`. The plugin will automatically read and inject this HTML. You can define the style and animation of this HTML as you wish.
+
+::: tip
+
+- You can use the same syntax as in `index.html`, such as the `VITE_APP_TITLE` variable, to get the application's title.
+- You must ensure there is an element with `id="__app-loading__"`.
+- Add a `hidden` class to the element with `id="__app-loading__"`.
+- You must ensure there is a `style[data-app-loading="inject-css"]` element.
+
+```html{1,4}
+
+
+
+
<%= VITE_APP_TITLE %>
+
+```
diff --git a/docs/src/en/guide/in-depth/locale.md b/docs/src/en/guide/in-depth/locale.md
new file mode 100644
index 00000000..98974be2
--- /dev/null
+++ b/docs/src/en/guide/in-depth/locale.md
@@ -0,0 +1,227 @@
+# Internationalization
+
+The project has integrated [Vue i18n](https://kazupon.github.io/vue-i18n/), and Chinese and English language packs have been configured.
+
+## IDE Plugin
+
+If you are using vscode as your development tool, it is recommended to install the [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) plugin. It can help you manage internationalization copy more conveniently. After installing this plugin, you can see the corresponding language content in your code in real-time:
+
+![](/public/guide/locale.png)
+
+## Configure Default Language
+
+You just need to override the default preferences. In the corresponding application, find the `src/preferences.ts` file and modify the value of `locale`:
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+ app: {
+ locale: 'en-US',
+ },
+});
+```
+
+## Dynamic Language Switching
+
+Switching languages consists of two parts:
+
+- Updating preferences
+- Loading the corresponding language pack
+
+```ts
+import type { SupportedLanguagesType } from '@vben/locales';
+import { loadLocaleMessages } from '@vben/locales';
+import { updatePreferences } from '@vben/preferences';
+
+async function updateLocale(value: string) {
+ // 1. Update preferences
+ const locale = value as SupportedLanguagesType;
+ updatePreferences({
+ app: {
+ locale,
+ },
+ });
+ // 2. Load the corresponding language pack
+ await loadLocaleMessages(locale);
+}
+
+updateLocale('en-US');
+```
+
+## Adding Translation Texts
+
+::: warning Attention
+
+- Do not place business translation texts inside `@vben/locales` to better manage business and general translation texts.
+- When adding new translation texts and multiple language packs are available, ensure to add the corresponding texts in all language packs.
+
+:::
+
+To add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example:
+
+**src/locales/langs/zh-CN.ts**
+
+````ts
+```json
+{
+ "about": {
+ "desc": "Vben Admin 是一个现代的管理模版。"
+ }
+}
+````
+
+**src/locales/langs/en-US.ts**
+
+````ts
+```json
+{
+ "about": {
+ "desc": "Vben Admin is a modern management template."
+ }
+}
+````
+
+## Using Translation Texts
+
+With `@vben/locales`, you can easily use translation texts:
+
+### In Code
+
+```vue
+
+
+
{{ $t('about.desc') }}
+
+
{{ item.title }}
+
+
+```
+
+## Adding a New Language Pack
+
+If you need to add a new language pack, follow these steps:
+
+- Add the corresponding language pack file in the `packages/locales/langs` directory, for example, `zh-TW.json`, and translate the respective texts.
+- In the corresponding application, locate the `src/locales/langs` file and add the new language pack `zh-TW.json`.
+- Add the corresponding language in `packages/constants/src/core.ts`:
+
+ ```ts
+ export interface LanguageOption {
+ label: string;
+ value: 'en-US' | 'zh-CN'; // [!code --]
+ value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+ }
+ export const SUPPORT_LANGUAGES: LanguageOption[] = [
+ {
+ label: '简体中文',
+ value: 'zh-CN',
+ },
+ {
+ label: 'English',
+ value: 'en-US',
+ },
+ {
+ label: '繁体中文', // [!code ++]
+ value: 'zh-TW', // [!code ++]
+ },
+ ];
+ ```
+
+- In `packages/locales/typing.ts`, add a new TypeScript type:
+
+ ```ts
+ export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
+ export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+ ```
+
+At this point, you can use the newly added language pack in the project.
+
+## Interface Language Switching Function
+
+If you want to disable the language switching display button on the interface, in the corresponding application, find the `src/preferences.ts` file and modify the value of `locale` accordingly:
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+ widget: {
+ languageToggle: false,
+ },
+});
+```
+
+## Remote Loading of Language Packs
+
+::: tip Tip
+
+When making interface requests through the project's built-in `request` tool, the default request header will include [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), allowing the server to dynamically internationalize data based on the request header.
+
+:::
+
+Each application has an independent language pack that can override the general language configuration. You can remotely load the corresponding language pack by finding the `src/locales/index.ts` file in the corresponding application and modifying the `loadMessages` method accordingly:
+
+```ts {3-4}
+async function loadMessages(lang: SupportedLanguagesType) {
+ const [appLocaleMessages] = await Promise.all([
+ // Modify here to load data via a remote interface
+ localesMap[lang](),
+ loadThirdPartyMessage(lang),
+ ]);
+ return appLocaleMessages.default;
+}
+```
+
+## Third-Party Language Packs
+
+Different applications may use third-party component libraries or plugins with varying internationalization methods, so they need to be handled differently. If you need to introduce a third-party language pack, you can find the `src/locales/index.ts` file in the corresponding application and modify the `loadThirdPartyMessage` method accordingly:
+
+```ts
+/**
+ * Load the dayjs language pack
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+ let locale;
+ switch (lang) {
+ case 'zh-CN': {
+ locale = await import('dayjs/locale/zh-cn');
+ break;
+ }
+ case 'en-US': {
+ locale = await import('dayjs/locale/en');
+ break;
+ }
+ // Default to using English
+ default: {
+ locale = await import('dayjs/locale/en');
+ }
+ }
+ if (locale) {
+ dayjs.locale(locale);
+ } else {
+ console.error(`Failed to load dayjs locale for ${lang}`);
+ }
+}
+```
+
+## Removing Internationalization
+
+Firstly, it is not recommended to remove internationalization, as it is a good development practice. However, if you really need to remove it, you can directly use Chinese copy and then retain the project's built-in language pack, which will not affect the overall development experience. The steps to remove internationalization are as follows:
+
+- Hide the language switching button on the interface, see: [Interface Language Switching Function](#interface-language-switching-function)
+- Modify the default language, see: [Configure Default Language](#configure-default-language)
+- Disable `vue-i18n` warning prompts, in the `src/locales/index.ts` file, modify `missingWarn` to `false`:
+
+ ```ts
+ async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+ await coreSetup(app, {
+ defaultLocale: preferences.app.locale,
+ loadMessages,
+ missingWarn: !import.meta.env.PROD, // [!code --]
+ missingWarn: false, // [!code ++]
+ ...options,
+ });
+ }
+ ```
diff --git a/docs/src/en/guide/in-depth/login.md b/docs/src/en/guide/in-depth/login.md
new file mode 100644
index 00000000..207e9497
--- /dev/null
+++ b/docs/src/en/guide/in-depth/login.md
@@ -0,0 +1,131 @@
+# Login
+
+This document explains how to customize the login page of your application.
+
+## Login Page Adjustment
+
+If you want to adjust the title, description, icon, and toolbar of the login page, you can do so by configuring the `props` parameter of the `AuthPageLayout` component.
+
+![login](/guide/login.png)
+
+You just need to configure the `props` parameter of `AuthPageLayout` in `src/router/routes/core.ts` within your application:
+
+```ts {4-8}
+ {
+ component: AuthPageLayout,
+ props: {
+ sloganImage: "xxx/xxx.png",
+ pageTitle: "开箱即用的大型中后台管理系统",
+ pageDescription: "工程化、高性能、跨组件库的前端模版",
+ toolbar: true,
+ toolbarList: () => ['color', 'language', 'layout', 'theme'],
+ }
+ // ...
+ },
+```
+
+::: tip
+
+If these configurations do not meet your needs, you can implement your own login page. Simply implement your own `AuthPageLayout`.
+
+:::
+
+## Login Form Adjustment
+
+If you want to adjust the content of the login form, you can configure the `AuthenticationLogin` component parameters in `src/views/_core/authentication/login.vue` within your application:
+
+```vue
+
+```
+
+::: details AuthenticationLogin Component Props
+
+```ts
+{
+ /**
+ * @en Verification code login path
+ */
+ codeLoginPath?: string;
+ /**
+ * @en Forget password path
+ */
+ forgetPasswordPath?: string;
+
+ /**
+ * @en Whether it is in loading state
+ */
+ loading?: boolean;
+
+ /**
+ * @en Password placeholder
+ */
+ passwordPlaceholder?: string;
+
+ /**
+ * @en QR code login path
+ */
+ qrCodeLoginPath?: string;
+
+ /**
+ * @en Registration path
+ */
+ registerPath?: string;
+
+ /**
+ * @en Whether to show verification code login
+ */
+ showCodeLogin?: boolean;
+ /**
+ * @en Whether to show forget password
+ */
+ showForgetPassword?: boolean;
+
+ /**
+ * @en Whether to show QR code login
+ */
+ showQrcodeLogin?: boolean;
+
+ /**
+ * @en Whether to show registration button
+ */
+ showRegister?: boolean;
+
+ /**
+ * @en Whether to show remember account
+ */
+ showRememberMe?: boolean;
+
+ /**
+ * @en Whether to show third-party login
+ */
+ showThirdPartyLogin?: boolean;
+
+ /**
+ * @en Login box subtitle
+ */
+ subTitle?: string;
+
+ /**
+ * @en Login box title
+ */
+ title?: string;
+
+ /**
+ * @en Username placeholder
+ */
+ usernamePlaceholder?: string;
+}
+```
+
+:::
+
+::: tip
+
+If these configurations do not meet your needs, you can implement your own login form and related login logic.
+
+:::
diff --git a/docs/src/en/guide/in-depth/theme.md b/docs/src/en/guide/in-depth/theme.md
new file mode 100644
index 00000000..6c2e23b9
--- /dev/null
+++ b/docs/src/en/guide/in-depth/theme.md
@@ -0,0 +1,1293 @@
+# Theme
+
+The framework is built on [shadcn-vue](https://www.shadcn-vue.com/themes.html) and [tailwindcss](https://tailwindcss.com/), offering a rich theme configuration. You can easily switch between various themes through simple configuration to meet personalized needs. You can choose to use CSS variables or Tailwind CSS utility classes for theme settings.
+
+## CSS Variables
+
+The project follows the theme configuration of [shadcn-vue](https://www.shadcn-vue.com/themes.html), for example:
+
+```html
+
+```
+
+We use a simple convention for colors. The `background` variable is used for the background color of components, and the `foreground` variable is used for text color.
+
+For the following components, `background` will be `hsl(var(--primary))`, and `foreground` will be `hsl(var(--primary-foreground))`.
+
+## Detailed List of CSS Variables
+
+::: warning Note
+
+The colors inside CSS variables must use the `hsl` format, such as `0 0% 100%`, without adding `hsl()` and `,`.
+
+:::
+
+You can check the list below to understand all the available variables.
+
+::: details Default theme CSS variables
+
+```css
+:root {
+ --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+ 'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+ 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+ /* Default background color of ...etc */
+ --background: 0 0% 100%;
+
+ /* Main area background color */
+ --background-deep: 210 11.11% 96.47%;
+ --foreground: 210 6% 21%;
+
+ /* Background color for */
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+
+ /* Background color for popovers such as , , */
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+
+ /* Muted backgrounds such as , and */
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ /* Theme Colors */
+
+ --primary: 211 91% 39%;
+ --primary-foreground: 0 0% 98%;
+
+ /* Used for destructive actions such as