diff --git a/frontend/api-docs.html b/frontend/api-docs.html
index 9f35080a..65ee57f7 100644
--- a/frontend/api-docs.html
+++ b/frontend/api-docs.html
@@ -3,7 +3,7 @@
- 3x-ui · API Docs
+ API Docs
diff --git a/frontend/inbounds.html b/frontend/inbounds.html
index 57485c92..9e8861fc 100644
--- a/frontend/inbounds.html
+++ b/frontend/inbounds.html
@@ -3,7 +3,7 @@
- 3x-ui · Inbounds
+ Inbounds
diff --git a/frontend/index.html b/frontend/index.html
index b2d45443..d13b400f 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -3,7 +3,7 @@
- 3x-ui
+ Overview
diff --git a/frontend/login.html b/frontend/login.html
index ba8e1e05..658f8d10 100644
--- a/frontend/login.html
+++ b/frontend/login.html
@@ -4,7 +4,7 @@
- 3x-ui — Sign in
+ Sign in
diff --git a/frontend/nodes.html b/frontend/nodes.html
index fb607b19..fec96dbc 100644
--- a/frontend/nodes.html
+++ b/frontend/nodes.html
@@ -3,7 +3,7 @@
- 3x-ui · Nodes
+ Nodes
diff --git a/frontend/settings.html b/frontend/settings.html
index da144ba7..0ef6413b 100644
--- a/frontend/settings.html
+++ b/frontend/settings.html
@@ -3,7 +3,7 @@
- 3x-ui · Settings
+ Settings
diff --git a/frontend/src/entries/api-docs.js b/frontend/src/entries/api-docs.js
index e5a22856..852bbc41 100644
--- a/frontend/src/entries/api-docs.js
+++ b/frontend/src/entries/api-docs.js
@@ -5,9 +5,11 @@ import 'ant-design-vue/dist/reset.css';
import { setupAxios } from '@/api/axios-init.js';
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import ApiDocsPage from '@/pages/api-docs/ApiDocsPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/entries/inbounds.js b/frontend/src/entries/inbounds.js
index 15b34d2e..8342f476 100644
--- a/frontend/src/entries/inbounds.js
+++ b/frontend/src/entries/inbounds.js
@@ -5,9 +5,11 @@ import 'ant-design-vue/dist/reset.css';
import { setupAxios } from '@/api/axios-init.js';
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import InboundsPage from '@/pages/inbounds/InboundsPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/entries/index.js b/frontend/src/entries/index.js
index 61d9dc12..8e14d2ae 100644
--- a/frontend/src/entries/index.js
+++ b/frontend/src/entries/index.js
@@ -7,9 +7,11 @@ import { setupAxios } from '@/api/axios-init.js';
// stored theme to / before Vue mounts.
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import IndexPage from '@/pages/index/IndexPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/entries/login.js b/frontend/src/entries/login.js
index ec90a9fb..6b8b0fc2 100644
--- a/frontend/src/entries/login.js
+++ b/frontend/src/entries/login.js
@@ -7,9 +7,11 @@ import { setupAxios } from '@/api/axios-init.js';
// stored theme to / before Vue renders anything.
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import LoginPage from '@/pages/login/LoginPage.vue';
setupAxios();
+applyDocumentTitle();
// Toasts attach to a #message div the page provides — keeps theme
// styling in sync with the rest of the panel.
diff --git a/frontend/src/entries/nodes.js b/frontend/src/entries/nodes.js
index 512643be..819fe9a9 100644
--- a/frontend/src/entries/nodes.js
+++ b/frontend/src/entries/nodes.js
@@ -5,9 +5,11 @@ import 'ant-design-vue/dist/reset.css';
import { setupAxios } from '@/api/axios-init.js';
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import NodesPage from '@/pages/nodes/NodesPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/entries/settings.js b/frontend/src/entries/settings.js
index 0c9a85a6..4a32bb7e 100644
--- a/frontend/src/entries/settings.js
+++ b/frontend/src/entries/settings.js
@@ -7,9 +7,11 @@ import { setupAxios } from '@/api/axios-init.js';
// stored theme to / before Vue mounts.
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import SettingsPage from '@/pages/settings/SettingsPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/entries/xray.js b/frontend/src/entries/xray.js
index 90af3e55..ba203da0 100644
--- a/frontend/src/entries/xray.js
+++ b/frontend/src/entries/xray.js
@@ -5,9 +5,11 @@ import 'ant-design-vue/dist/reset.css';
import { setupAxios } from '@/api/axios-init.js';
import '@/composables/useTheme.js';
import { i18n } from '@/i18n/index.js';
+import { applyDocumentTitle } from '@/utils';
import XrayPage from '@/pages/xray/XrayPage.vue';
setupAxios();
+applyDocumentTitle();
const messageContainer = document.getElementById('message');
if (messageContainer) {
diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js
index 61027017..589a1610 100644
--- a/frontend/src/utils/index.js
+++ b/frontend/src/utils/index.js
@@ -75,6 +75,13 @@ export class HttpUtil {
}
}
+export function applyDocumentTitle() {
+ const host = window.location.hostname;
+ if (!host) return;
+ const current = document.title.trim();
+ document.title = current ? `${host} - ${current}` : host;
+}
+
export class PromiseUtil {
static async sleep(timeout) {
await new Promise(resolve => {
diff --git a/frontend/xray.html b/frontend/xray.html
index 3c16d29f..a5739c02 100644
--- a/frontend/xray.html
+++ b/frontend/xray.html
@@ -3,7 +3,7 @@
- 3x-ui · Xray
+ Xray Config