From 28513a51e302309036701d15d332c925302aa9cc Mon Sep 17 00:00:00 2001 From: abdulrahman Date: Wed, 13 May 2026 09:39:44 +0300 Subject: [PATCH] style(api-docs): redesign TOC, section icons, endpoint rows, and code blocks with ultra-dark support --- frontend/src/pages/api-docs/ApiDocsPage.vue | 249 ++++++++++++++++-- frontend/src/pages/api-docs/CodeBlock.vue | 90 ++++--- frontend/src/pages/api-docs/EndpointRow.vue | 60 ++++- .../src/pages/api-docs/EndpointSection.vue | 58 +++- frontend/src/pages/api-docs/endpoints.js | 12 +- 5 files changed, 382 insertions(+), 87 deletions(-) diff --git a/frontend/src/pages/api-docs/ApiDocsPage.vue b/frontend/src/pages/api-docs/ApiDocsPage.vue index 9a5f958e..a3078b8e 100644 --- a/frontend/src/pages/api-docs/ApiDocsPage.vue +++ b/frontend/src/pages/api-docs/ApiDocsPage.vue @@ -1,5 +1,5 @@ @@ -150,7 +199,7 @@ onMounted(() => { API Token - +
Regenerate - +
 {
 
             
 
             
@@ -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,91 @@ 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-nav.toc-stuck {
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
 .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 +543,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 +584,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 d42b3f5f..60e5491c 100644
--- a/frontend/src/pages/api-docs/CodeBlock.vue
+++ b/frontend/src/pages/api-docs/CodeBlock.vue
@@ -50,10 +50,13 @@ async function copyCode() {
 
 
@@ -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 7ddcf41c..e0966d79 100644
--- a/frontend/src/pages/api-docs/endpoints.js
+++ b/frontend/src/pages/api-docs/endpoints.js
@@ -68,7 +68,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 X-Forwarded-Host / X-Forwarded-Proto, so callers behind a reverse proxy get the correct external host in returned URLs.',
     endpoints: [
@@ -288,7 +288,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: [
@@ -487,7 +487,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: [
@@ -568,7 +568,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: [
@@ -636,7 +636,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: [
@@ -696,7 +696,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: [