{
- {{ visibleSections }} / {{ endpointCount }} endpoints
+ {{ visibleEndpoints }} / {{ endpointCount }} endpoints
@@ -213,16 +262,27 @@ onMounted(() => {
@@ -273,20 +333,25 @@ onMounted(() => {
}
.docs-header {
- margin-bottom: 18px;
+ margin-bottom: 20px;
+ padding: 24px;
+ background: var(--bg-card);
+ border: 1px solid rgba(128, 128, 128, 0.12);
+ border-radius: 10px;
}
.docs-title {
- font-size: 26px;
- font-weight: 700;
+ font-size: 28px;
+ font-weight: 800;
margin: 0 0 8px;
color: rgba(0, 0, 0, 0.88);
+ letter-spacing: -0.3px;
}
.docs-lead {
margin: 0;
color: rgba(0, 0, 0, 0.65);
- line-height: 1.6;
+ line-height: 1.65;
font-size: 14px;
}
@@ -310,7 +375,8 @@ onMounted(() => {
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
- margin-bottom: 8px;
+ margin-bottom: 10px;
+ min-height: 32px;
}
.token-card-title {
@@ -321,6 +387,13 @@ onMounted(() => {
font-size: 14px;
}
+.token-actions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
.token-value {
background: rgba(128, 128, 128, 0.08);
border: 1px solid rgba(128, 128, 128, 0.15);
@@ -377,32 +450,87 @@ onMounted(() => {
.toc-nav {
display: flex;
flex-wrap: wrap;
- align-items: center;
- gap: 8px 14px;
+ align-items: flex-start;
+ gap: 8px 12px;
padding: 12px 16px;
- background: rgba(128, 128, 128, 0.08);
- border-radius: 6px;
+ background: var(--bg-card);
+ border: 1px solid rgba(128, 128, 128, 0.12);
+ border-radius: 8px;
margin-bottom: 16px;
}
.toc-label {
- font-size: 12px;
+ font-size: 11px;
font-weight: 600;
text-transform: uppercase;
- letter-spacing: 0.5px;
+ letter-spacing: 0.6px;
color: rgba(0, 0, 0, 0.5);
+ padding-top: 3px;
+ flex-shrink: 0;
+}
+
+.toc-links {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
}
.toc-link {
- color: #1677ff;
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ padding: 4px 10px;
+ border-radius: 20px;
+ font-size: 12.5px;
+ color: rgba(0, 0, 0, 0.65);
+ background: rgba(128, 128, 128, 0.06);
+ border: 1px solid transparent;
text-decoration: none;
cursor: pointer;
- font-size: 13px;
+ transition: all 0.2s;
+ white-space: nowrap;
}
.toc-link:hover {
- color: #4096ff;
- text-decoration: underline;
+ background: rgba(22, 119, 255, 0.08);
+ color: #1677ff;
+ border-color: rgba(22, 119, 255, 0.2);
+}
+
+.toc-link.active {
+ background: rgba(22, 119, 255, 0.12);
+ color: #1677ff;
+ border-color: rgba(22, 119, 255, 0.3);
+ font-weight: 600;
+}
+
+.toc-icon {
+ font-size: 13px;
+ opacity: 0.8;
+}
+
+.toc-text {
+ font-size: 12.5px;
+}
+
+.toc-badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 18px;
+ height: 18px;
+ padding: 0 5px;
+ border-radius: 9px;
+ font-size: 10.5px;
+ font-weight: 700;
+ background: rgba(22, 119, 255, 0.12);
+ color: #1677ff;
+ line-height: 1;
+}
+
+.toc-link.active .toc-badge {
+ background: #1677ff;
+ color: #fff;
}
@@ -411,16 +539,40 @@ body.dark .docs-title {
color: rgba(255, 255, 255, 0.92);
}
+html[data-theme='ultra-dark'] .docs-title {
+ color: rgba(255, 255, 255, 0.95);
+}
+
+body.dark .docs-header {
+ background: #252526;
+ border-color: rgba(255, 255, 255, 0.08);
+}
+
+html[data-theme='ultra-dark'] .docs-header {
+ background: #0a0a0a;
+ border-color: rgba(255, 255, 255, 0.06);
+}
+
body.dark .docs-lead,
body.dark .token-hint {
color: rgba(255, 255, 255, 0.7);
}
+html[data-theme='ultra-dark'] .docs-lead,
+html[data-theme='ultra-dark'] .token-hint {
+ color: rgba(255, 255, 255, 0.75);
+}
+
body.dark .docs-lead code,
body.dark .token-hint code {
background: rgba(255, 255, 255, 0.1);
}
+html[data-theme='ultra-dark'] .docs-lead code,
+html[data-theme='ultra-dark'] .token-hint code {
+ background: rgba(255, 255, 255, 0.12);
+}
+
body.dark .token-value,
body.dark .code-block {
background: rgba(255, 255, 255, 0.04);
@@ -428,11 +580,58 @@ body.dark .code-block {
color: rgba(255, 255, 255, 0.88);
}
+html[data-theme='ultra-dark'] .token-value,
+html[data-theme='ultra-dark'] .code-block {
+ background: rgba(255, 255, 255, 0.02);
+ border-color: rgba(255, 255, 255, 0.08);
+}
+
body.dark .toc-nav {
- background: rgba(255, 255, 255, 0.04);
+ background: #252526;
+ border-color: rgba(255, 255, 255, 0.08);
+}
+
+html[data-theme='ultra-dark'] .toc-nav {
+ background: #0a0a0a;
+ border-color: rgba(255, 255, 255, 0.06);
}
body.dark .toc-label {
color: rgba(255, 255, 255, 0.55);
}
+
+html[data-theme='ultra-dark'] .toc-label {
+ color: rgba(255, 255, 255, 0.6);
+}
+
+body.dark .toc-link {
+ color: rgba(255, 255, 255, 0.65);
+ background: rgba(255, 255, 255, 0.06);
+}
+
+html[data-theme='ultra-dark'] .toc-link {
+ background: rgba(255, 255, 255, 0.04);
+}
+
+body.dark .toc-link:hover {
+ background: rgba(88, 166, 255, 0.12);
+ color: #58a6ff;
+ border-color: rgba(88, 166, 255, 0.25);
+}
+
+body.dark .toc-link.active {
+ background: rgba(88, 166, 255, 0.15);
+ color: #58a6ff;
+ border-color: rgba(88, 166, 255, 0.35);
+}
+
+body.dark .toc-badge {
+ background: rgba(88, 166, 255, 0.15);
+ color: #58a6ff;
+}
+
+body.dark .toc-link.active .toc-badge {
+ background: #58a6ff;
+ color: #0d1117;
+}
diff --git a/frontend/src/pages/api-docs/CodeBlock.vue b/frontend/src/pages/api-docs/CodeBlock.vue
index b728e854..446016c7 100644
--- a/frontend/src/pages/api-docs/CodeBlock.vue
+++ b/frontend/src/pages/api-docs/CodeBlock.vue
@@ -50,10 +50,13 @@ async function copyCode() {
-
+
+ {{ lang.toUpperCase() }}
+
+
@@ -63,30 +66,40 @@ async function copyCode() {
position: relative;
border-radius: 6px;
overflow: hidden;
+ border: 1px solid rgba(128, 128, 128, 0.15);
+}
+
+.code-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 4px 8px;
+ background: rgba(128, 128, 128, 0.06);
+ border-bottom: 1px solid rgba(128, 128, 128, 0.1);
+}
+
+.lang-badge {
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 0.5px;
+ color: rgba(0, 0, 0, 0.4);
+ text-transform: uppercase;
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.copy-btn {
- position: absolute;
- top: 6px;
- right: 6px;
- z-index: 1;
display: inline-flex;
align-items: center;
justify-content: center;
- width: 28px;
- height: 28px;
- border: 1px solid rgba(128, 128, 128, 0.2);
+ width: 26px;
+ height: 26px;
+ border: 1px solid rgba(128, 128, 128, 0.15);
border-radius: 4px;
- background: rgba(255, 255, 255, 0.85);
- color: rgba(0, 0, 0, 0.5);
+ background: rgba(255, 255, 255, 0.7);
+ color: rgba(0, 0, 0, 0.45);
cursor: pointer;
- font-size: 13px;
- opacity: 0;
- transition: opacity 0.15s, background 0.15s, color 0.15s;
-}
-
-.code-block-wrapper:hover .copy-btn {
- opacity: 1;
+ font-size: 12px;
+ transition: all 0.15s;
}
.copy-btn:hover {
@@ -96,27 +109,24 @@ async function copyCode() {
}
.copy-btn.copied {
- opacity: 1;
background: #52c41a;
color: #fff;
border-color: #52c41a;
}
.code-block {
- background: rgba(128, 128, 128, 0.08);
- border: 1px solid rgba(128, 128, 128, 0.15);
- border-radius: 6px;
- padding: 12px;
+ background: rgba(128, 128, 128, 0.04);
+ padding: 10px 12px;
margin: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12.5px;
- line-height: 1.55;
+ line-height: 1.6;
white-space: pre-wrap;
word-break: break-word;
overflow-x: auto;
+ border: none;
+ border-radius: 0;
}
-
-
diff --git a/frontend/src/pages/api-docs/endpoints.js b/frontend/src/pages/api-docs/endpoints.js
index c92ee389..24259bbb 100644
--- a/frontend/src/pages/api-docs/endpoints.js
+++ b/frontend/src/pages/api-docs/endpoints.js
@@ -69,7 +69,7 @@ export const sections = [
{
id: 'inbounds',
- title: 'Inbounds API',
+ title: 'Inbounds',
description:
'Manage inbound configurations and their clients. All endpoints live under /panel/api/inbounds and require a logged-in session or Bearer token. Link-generating endpoints honour forwarded headers only when the request comes from a configured trusted proxy.',
endpoints: [
@@ -193,6 +193,14 @@ export const sections = [
body:
'{\n "id": 1,\n "settings": "{\\"clients\\":[{\\"id\\":\\"uuid-here\\",\\"email\\":\\"user1\\",\\"limitIp\\":2,\\"totalGB\\":10737418240,\\"expiryTime\\":1735689600000,\\"enable\\":true}]}"\n}',
},
+ {
+ method: 'POST',
+ path: '/panel/api/inbounds/:id/resetTraffic',
+ summary: 'Zero out upload + download counters for a single inbound. Does not touch per-client counters.',
+ params: [
+ { name: 'id', in: 'path', type: 'number', desc: 'Inbound ID.' },
+ ],
+ },
{
method: 'POST',
path: '/panel/api/inbounds/:id/resetClientTraffic/:email',
@@ -289,7 +297,7 @@ export const sections = [
{
id: 'server',
- title: 'Server API',
+ title: 'Server',
description:
'System status, log retrieval, certificate generators, Xray binary management, and backup/restore. All under /panel/api/server.',
endpoints: [
@@ -488,7 +496,7 @@ export const sections = [
{
id: 'nodes',
- title: 'Nodes API',
+ title: 'Nodes',
description:
'Manage remote 3x-ui panels acting as nodes for a central panel. All endpoints under /panel/api/nodes.',
endpoints: [
@@ -569,7 +577,7 @@ export const sections = [
{
id: 'customGeo',
- title: 'Custom Geo API',
+ title: 'Custom Geo',
description:
'Manage user-supplied GeoIP / GeoSite source files. All endpoints under /panel/api/custom-geo.',
endpoints: [
@@ -637,7 +645,7 @@ export const sections = [
{
id: 'settings',
- title: 'Settings API',
+ title: 'Settings',
description:
'Panel configuration, user credentials, and API token management. All endpoints live under /panel/setting and require a logged-in session or Bearer token.',
endpoints: [
@@ -697,7 +705,7 @@ export const sections = [
{
id: 'xraySettings',
- title: 'Xray Settings API',
+ title: 'Xray Settings',
description:
'Xray configuration template, outbound management, Warp/Nord integration, and config testing. All endpoints under /panel/xray.',
endpoints: [