diff --git a/web/assets/js/subscription.js b/web/assets/js/subscription.js
index c7627837..b79d361c 100644
--- a/web/assets/js/subscription.js
+++ b/web/assets/js/subscription.js
@@ -138,14 +138,14 @@
return `streisand://import/${encodeURIComponent(this.app.subUrl)}`;
},
v2raytunUrl() {
- return this.app.subUrl;
+ return this.app.subUrl;
},
npvtunUrl() {
- return this.app.subUrl;
+ return this.app.subUrl;
},
- happUrl() {
- return `happ://add/${encodeURIComponent(this.app.subUrl)}`;
- }
+ happUrl() {
+ return `happ://add/${encodeURIComponent(this.app.subUrl)}`;
+ }
},
methods: {
renderLink,
diff --git a/web/html/common/page.html b/web/html/common/page.html
index 0af63afb..058682d5 100644
--- a/web/html/common/page.html
+++ b/web/html/common/page.html
@@ -24,6 +24,40 @@
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Vazirmatn', 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
+
+ /* mobile touch scrolling for tabs */
+ @media (max-width: 576px) {
+ .ant-tabs-nav-container {
+ overflow-x: auto !important;
+ -webkit-overflow-scrolling: touch;
+ scroll-behavior: smooth;
+ overscroll-behavior-x: contain;
+ white-space: nowrap;
+ max-width: 100%;
+ padding: 0 !important; /* Remove padding for arrows */
+ }
+ .ant-tabs-nav-wrap {
+ overflow: visible !important;
+ padding: 0 !important;
+ }
+ .ant-tabs-nav-scroll {
+ overflow: visible !important;
+ box-shadow: none !important;
+ }
+ .ant-tabs-nav {
+ display: flex !important;
+ transform: none !important; /* Disable JS transform */
+ width: auto !important;
+ margin: 0 !important;
+ }
+ .ant-tabs-tab-prev,
+ .ant-tabs-tab-next {
+ display: none !important; /* Hide arrows */
+ }
+ .ant-tabs-nav-container::-webkit-scrollbar {
+ display: none;
+ }
+ }
{{ .host }} – {{ i18n .title}}
{{ end }}
diff --git a/web/html/form/protocol/vless.html b/web/html/form/protocol/vless.html
index bdf75be3..fc9c3852 100644
--- a/web/html/form/protocol/vless.html
+++ b/web/html/form/protocol/vless.html
@@ -1,6 +1,5 @@
{{define "form/vless"}}
-
+
{{template "form/client"}}
@@ -22,115 +21,103 @@
-
-
-
- X25519 (not
- Post-Quantum)
- ML-KEM-768
- (Post-Quantum)
-
-
-
-
-
-
-
-
-
-
- Get New
- keys
- Clear
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ X25519 (not
+ Post-Quantum)
+ ML-KEM-768
+ (Post-Quantum)
+
+
+
+
+
+
+
+
+
+
+ Get New
+ keys
+ Clear
+
+
+
+
+
+
+
+
+
+
+
-
-
- Fallback [[ index + 1 ]] inbound.settings.delFallback(index)"
- :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- updateTestseed(0, val)" :min="0" :max="9999"
- :style="{ width: '100%' }"
- placeholder="900" addon-before="[0]">
-
-
- updateTestseed(1, val)" :min="0" :max="9999"
- :style="{ width: '100%' }"
- placeholder="500" addon-before="[1]">
-
-
- updateTestseed(2, val)" :min="0" :max="9999"
- :style="{ width: '100%' }"
- placeholder="900" addon-before="[2]">
-
-
- updateTestseed(3, val)" :min="0" :max="9999"
- :style="{ width: '100%' }"
- placeholder="256" addon-before="[3]">
-
-
-
-
- Rand
-
-
- Reset
-
-
-
-
-
-
+
+
+ Fallback [[ index + 1 ]] inbound.settings.delFallback(index)"
+ :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ updateTestseed(0, val)" :min="0" :max="9999" :style="{ width: '100%' }"
+ placeholder="900" addon-before="[0]">
+
+
+ updateTestseed(1, val)" :min="0" :max="9999" :style="{ width: '100%' }"
+ placeholder="500" addon-before="[1]">
+
+
+ updateTestseed(2, val)" :min="0" :max="9999" :style="{ width: '100%' }"
+ placeholder="900" addon-before="[2]">
+
+
+ updateTestseed(3, val)" :min="0" :max="9999" :style="{ width: '100%' }"
+ placeholder="256" addon-before="[3]">
+
+
+
+
+ Rand
+
+
+ Reset
+
+
+
+
+
+
{{end}}
\ No newline at end of file
diff --git a/web/html/inbounds.html b/web/html/inbounds.html
index 4e1149ae..eeffd98d 100644
--- a/web/html/inbounds.html
+++ b/web/html/inbounds.html
@@ -1608,24 +1608,9 @@
// Listen for traffic updates
window.wsClient.on('traffic', (payload) => {
- if (payload && payload.clientTraffics && Array.isArray(payload.clientTraffics)) {
- // Update client traffic statistics
- payload.clientTraffics.forEach(clientTraffic => {
- const dbInbound = this.dbInbounds.find(ib => {
- if (!ib) return false;
- const clients = this.getInboundClients(ib);
- return clients && Array.isArray(clients) && clients.some(c => c && c.email === clientTraffic.email);
- });
- if (dbInbound && dbInbound.clientStats && Array.isArray(dbInbound.clientStats)) {
- const stats = dbInbound.clientStats.find(s => s && s.email === clientTraffic.email);
- if (stats) {
- stats.up = clientTraffic.up || stats.up;
- stats.down = clientTraffic.down || stats.down;
- stats.total = clientTraffic.total || stats.total;
- }
- }
- });
- }
+ // Note: Do NOT update total consumed traffic (stats.up, stats.down) from this event
+ // because clientTraffics contains delta/incremental values, not total accumulated values.
+ // Total traffic is updated via the 'inbounds' event which contains accumulated values from database.
// Update online clients list in real-time
if (payload && Array.isArray(payload.onlineClients)) {
@@ -1645,8 +1630,6 @@
}
});
- // Notifications disabled - white notifications are not needed
-
// Fallback to polling if WebSocket fails
window.wsClient.on('error', () => {
console.warn('WebSocket connection failed, falling back to polling');
diff --git a/web/html/settings/panel/subscription/subpage.html b/web/html/settings/panel/subscription/subpage.html
index 0043d0d2..222352ff 100644
--- a/web/html/settings/panel/subscription/subpage.html
+++ b/web/html/settings/panel/subscription/subpage.html
@@ -20,28 +20,20 @@
-
{{ i18n "pages.settings.language"
}}
-
-
-
-
+
+
+
@@ -53,42 +45,31 @@
-
-
+
+
-
+
{{ i18n
"pages.settings.subSettings"}}
-
-
-
+
-
+
{{ i18n
"pages.settings.subSettings"}}
Json
-
-
+
@@ -100,45 +81,36 @@
- [[
+ [[
app.sId
]]
-
+
{{ i18n
"subscription.unlimited" }}
- [[
+ [[
isActive ? '{{ i18n
"subscription.active" }}' : '{{ i18n
"subscription.inactive" }}'
]]
- [[
+ [[
app.download
]]
- [[
+ [[
app.upload
]]
- [[ app.used
+ [[ app.used
]]
- [[
+ [[
app.total
]]
- [[
+ [[
app.remained ]]
-
+
[[ IntlUtil.formatDate(app.lastOnlineMs) ]]
@@ -146,8 +118,7 @@
-
-
+
{{ i18n "subscription.noExpiry" }}
@@ -160,32 +131,48 @@
-
-
-
-
[[ linkName(link, idx)
- ]]
+
+
+
+ [[ linkName(link, idx) ]]
+
+
+ [[ link ]]
-
-
+
+
+
-
-
+
+
+ :style="{ marginTop: isMobile ? '6px' : 0 }" size="large" type="primary">
Android
-
+
V2Box
Sing-box
V2RayTun
- NPV
+ NPV
Tunnel
- Happ
+ Happ
-
+
+ :style="{ marginTop: isMobile ? '6px' : 0 }" size="large" type="primary">
iOS
-
+
Shadowrocket
- V2Box
+ V2Box
Streisand
V2RayTun
- NPV
+ NPV
Tunnel
- Happ
+ Happ
@@ -240,17 +220,12 @@
-
-