diff --git a/AGENTS.md b/AGENTS.md
index 6214b9a..240fdcf 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -32,6 +32,8 @@ This version has breaking changes — APIs, conventions, and file structure may
## Learned User Preferences
- 占成/授信/回水/上限等数值字段用 `AdminNumericStepper`(± 步进 + 可手输),勿单独裸 `input[type=number]`。
+- 对外文档(接入 + 后台运营手册)禁用 RBAC slug(如 `prd.settlement.agent.manage`);对客户称「贵司」;排版忌 AI 感,正文对比度与字号可读优先。
+- 文档 i18n:`useTranslation` 须显式 `ns`;`returnObjects` 列表用 `Array.isArray` 守卫;避免节名与表头 key 冲突(如 `billStatus`)。
## Learned Workspace Facts
@@ -39,5 +41,11 @@ This version has breaking changes — APIs, conventions, and file structure may
- 超管判定用登录态 `is_super_admin`,勿用站点角色或 `admin_user_site_roles` 绑定推断。
- 站点管理员(`profile.site != null`)代理 UI 绕过选中代理的 `can_create_*` 门控,按自身 manage 权限展示 Tab/操作。
- 站点管理员在代理下创建玩家须传 `agent_node_id`(与超管同逻辑),勿默认挂根代理。
-- 客户接入文档公开站:`/docs`(首页)、`/docs/integration`(接入正文),无需 `/admin` 登录;旧 `/admin/docs/integration-guide` 重定向至此。
+- 客户对外文档:`/docs`(首页)、`/docs/integration`(API 接入)、`/docs/admin`(后台运营手册),均公开免 `/admin` 登录;读者为接入方技术与站点运营/代理,非内部运维;旧 `/admin/docs/integration-guide` 重定向 `/docs/integration`;顶栏「管理后台」链 `/admin`(勿 `/admin/login`)。
- `SettlementBillRow` 无 `currency_code`;账单金额展示用玩家 `default_currency`。
+- 浏览器 `/api/v1/*` 由 Next 转发到 `LOTTERY_API_UPSTREAM`;与本地 Postgres 对账前须确认 upstream 与所查库一致。
+- 接入文档页静态内容校验用 `document.body.innerText`;`DocCode` 非裸 `
/`,勿只查 code 选择器。
+- Docs 侧栏粘性定位用 CSS 变量 `--docs-sticky-top`(含顶栏/header 偏移)。
+- Tanumo 联调/生产默认:H5 `https://front.tanumo.com`、API `https://lotterylaravel.tanumo.com`、管理端/文档 `https://lotteryadmin.tanumo.com`。
+- 接入文档 SSO:无「登录换票」;主站 JWT 直传 H5/iframe,`GET /api/v1/player/me` 自动建档;iframe 约定 token 在顶层 `data.token`;勿引用 main-site/monorepo 等内部仓库路径。
+- 风控页默认:占用流水按注单聚合;风险池仅显示有占用/高风险;组合明细放注单详情二级页。
diff --git a/src/api/admin-risk.ts b/src/api/admin-risk.ts
index e506e88..b329bad 100644
--- a/src/api/admin-risk.ts
+++ b/src/api/admin-risk.ts
@@ -15,6 +15,7 @@ export type AdminRiskPoolListQuery = {
per_page?: number;
sold_out_only?: boolean;
high_risk_only?: boolean;
+ active_only?: boolean;
normalized_number?: string;
sort?: "usage_desc" | "locked_desc" | "remaining_asc" | "number_asc";
};
@@ -29,6 +30,7 @@ export async function getAdminRiskPools(
per_page: q.per_page,
sold_out_only: q.sold_out_only === true ? 1 : undefined,
high_risk_only: q.high_risk_only === true ? 1 : undefined,
+ active_only: q.active_only === true ? 1 : undefined,
normalized_number: q.normalized_number || undefined,
sort: q.sort,
},
@@ -58,8 +60,10 @@ export async function postAdminRiskPoolRecover(
export type AdminRiskLockLogQuery = {
page?: number;
per_page?: number;
+ group_by?: "ticket" | "entry";
action_type?: "lock" | "release";
normalized_number?: string;
+ ticket_item_id?: number;
};
export async function getAdminRiskPoolLockLogs(
@@ -72,8 +76,10 @@ export async function getAdminRiskPoolLockLogs(
params: {
page: q.page,
per_page: q.per_page,
+ group_by: q.group_by ?? "ticket",
action_type: q.action_type,
normalized_number: q.normalized_number,
+ ticket_item_id: q.ticket_item_id,
},
},
);
diff --git a/src/api/admin-ticket-detail.ts b/src/api/admin-ticket-detail.ts
new file mode 100644
index 0000000..69a255b
--- /dev/null
+++ b/src/api/admin-ticket-detail.ts
@@ -0,0 +1,10 @@
+import { adminRequest } from "@/lib/admin-http";
+
+import type { AdminTicketItemDetail } from "@/types/api/admin-tickets";
+
+const A = `/admin`;
+
+export async function getAdminTicketItem(ticketNo: string): Promise {
+ const encoded = encodeURIComponent(ticketNo);
+ return adminRequest.get(`${A}/tickets/${encoded}`);
+}
diff --git a/src/app/admin/(shell)/agents/layout.tsx b/src/app/admin/(shell)/agents/layout.tsx
index a8f835e..a479a9b 100644
--- a/src/app/admin/(shell)/agents/layout.tsx
+++ b/src/app/admin/(shell)/agents/layout.tsx
@@ -4,7 +4,7 @@ import { AgentsSubnav } from "@/modules/agents/agents-subnav";
export default function AdminAgentsLayout({ children }: { children: ReactNode }) {
return (
-
+
diff --git a/src/app/admin/(shell)/agents/list/page.tsx b/src/app/admin/(shell)/agents/list/page.tsx
index 9bdecd8..72544f4 100644
--- a/src/app/admin/(shell)/agents/list/page.tsx
+++ b/src/app/admin/(shell)/agents/list/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { AgentsDirectoryConsole } from "@/modules/agents/agents-directory-console";
import { buildPageMetadata } from "@/lib/page-metadata";
-export const metadata: Metadata = buildPageMetadata("agents", "directoryTitle");
+export const metadata: Metadata = buildPageMetadata("agents", "listTitle");
export default function AgentsListPage() {
return
;
diff --git a/src/app/admin/(shell)/draws/[drawId]/risk/pools/page.tsx b/src/app/admin/(shell)/draws/[drawId]/risk/pools/page.tsx
index 42b8691..fa4c686 100644
--- a/src/app/admin/(shell)/draws/[drawId]/risk/pools/page.tsx
+++ b/src/app/admin/(shell)/draws/[drawId]/risk/pools/page.tsx
@@ -4,10 +4,10 @@ import {
} from "@/modules/risk/risk-pools-console";
function parsePoolFilter(raw: string | undefined): RiskPoolListFilter {
- if (raw === "sold_out" || raw === "high_risk") {
+ if (raw === "sold_out" || raw === "high_risk" || raw === "all" || raw === "active") {
return raw;
}
- return "all";
+ return "active";
}
export default async function AdminDrawRiskPoolsPage(props: {
@@ -24,7 +24,7 @@ export default async function AdminDrawRiskPoolsPage(props: {
drawId={id}
titleKey="allPoolsPageTitle"
initialFilter={filter}
- defaultSort={filter === "high_risk" ? "usage_desc" : "number_asc"}
+ defaultSort={filter === "high_risk" || filter === "active" ? "usage_desc" : "number_asc"}
allowSortChange
/>
);
diff --git a/src/app/admin/(shell)/tickets/[ticketNo]/page.tsx b/src/app/admin/(shell)/tickets/[ticketNo]/page.tsx
new file mode 100644
index 0000000..5c1b818
--- /dev/null
+++ b/src/app/admin/(shell)/tickets/[ticketNo]/page.tsx
@@ -0,0 +1,22 @@
+import { AdminPermissionGate } from "@/components/admin/admin-permission-gate";
+import { ModuleScaffold } from "@/components/admin/module-scaffold";
+import { PRD_TICKETS_ACCESS_ANY } from "@/lib/admin-prd";
+import { TicketDetailConsole } from "@/modules/tickets/ticket-detail-console";
+import { buildPageMetadata } from "@/lib/page-metadata";
+import type { Metadata } from "next";
+
+export const metadata: Metadata = buildPageMetadata("tickets", "detailTitle");
+
+export default async function AdminTicketDetailPage(props: {
+ params: Promise<{ ticketNo: string }>;
+}) {
+ const { ticketNo } = await props.params;
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/app/docs/admin/agents/page.tsx b/src/app/docs/admin/agents/page.tsx
new file mode 100644
index 0000000..dfd0436
--- /dev/null
+++ b/src/app/docs/admin/agents/page.tsx
@@ -0,0 +1,5 @@
+import { AdminAgentsDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsAgentsPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/config/page.tsx b/src/app/docs/admin/config/page.tsx
new file mode 100644
index 0000000..ff4bcae
--- /dev/null
+++ b/src/app/docs/admin/config/page.tsx
@@ -0,0 +1,5 @@
+import { AdminConfigDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsConfigPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/draws/page.tsx b/src/app/docs/admin/draws/page.tsx
new file mode 100644
index 0000000..7e05acc
--- /dev/null
+++ b/src/app/docs/admin/draws/page.tsx
@@ -0,0 +1,5 @@
+import { AdminDrawsDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsDrawsPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/faq/page.tsx b/src/app/docs/admin/faq/page.tsx
new file mode 100644
index 0000000..7505822
--- /dev/null
+++ b/src/app/docs/admin/faq/page.tsx
@@ -0,0 +1,5 @@
+import { AdminFaqDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsFaqPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/fund-operations/page.tsx b/src/app/docs/admin/fund-operations/page.tsx
new file mode 100644
index 0000000..df26b84
--- /dev/null
+++ b/src/app/docs/admin/fund-operations/page.tsx
@@ -0,0 +1,5 @@
+import { AdminFundOperationsDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsFundOperationsPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/layout.tsx b/src/app/docs/admin/layout.tsx
new file mode 100644
index 0000000..8d84329
--- /dev/null
+++ b/src/app/docs/admin/layout.tsx
@@ -0,0 +1,13 @@
+import type { ReactNode } from "react";
+
+import { DocsSidebar } from "@/components/docs/docs-sidebar";
+import { DocsBody } from "@/components/docs/docs-shell";
+import { ADMIN_DOCS_NAV_GROUPS } from "@/lib/admin-docs-nav";
+
+export default function AdminDocsLayout({ children }: { children: ReactNode }): React.ReactElement {
+ return (
+
}>
+ {children}
+
+ );
+}
diff --git a/src/app/docs/admin/manual-review/page.tsx b/src/app/docs/admin/manual-review/page.tsx
new file mode 100644
index 0000000..259ce4b
--- /dev/null
+++ b/src/app/docs/admin/manual-review/page.tsx
@@ -0,0 +1,5 @@
+import { AdminManualReviewDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsManualReviewPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/page.tsx b/src/app/docs/admin/page.tsx
new file mode 100644
index 0000000..0a59006
--- /dev/null
+++ b/src/app/docs/admin/page.tsx
@@ -0,0 +1,5 @@
+import { AdminOverviewDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsOverviewPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/players/page.tsx b/src/app/docs/admin/players/page.tsx
new file mode 100644
index 0000000..58940e1
--- /dev/null
+++ b/src/app/docs/admin/players/page.tsx
@@ -0,0 +1,5 @@
+import { AdminPlayersDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsPlayersPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/reports/page.tsx b/src/app/docs/admin/reports/page.tsx
new file mode 100644
index 0000000..6fc59f5
--- /dev/null
+++ b/src/app/docs/admin/reports/page.tsx
@@ -0,0 +1,5 @@
+import { AdminReportsDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsReportsPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/roles/page.tsx b/src/app/docs/admin/roles/page.tsx
new file mode 100644
index 0000000..a2e50aa
--- /dev/null
+++ b/src/app/docs/admin/roles/page.tsx
@@ -0,0 +1,5 @@
+import { AdminRolesDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsRolesPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/settlement-center/page.tsx b/src/app/docs/admin/settlement-center/page.tsx
new file mode 100644
index 0000000..585b3cf
--- /dev/null
+++ b/src/app/docs/admin/settlement-center/page.tsx
@@ -0,0 +1,5 @@
+import { AdminSettlementCenterDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsSettlementCenterPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/site-setup/page.tsx b/src/app/docs/admin/site-setup/page.tsx
new file mode 100644
index 0000000..1dddb4c
--- /dev/null
+++ b/src/app/docs/admin/site-setup/page.tsx
@@ -0,0 +1,5 @@
+import { AdminSiteSetupDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsSiteSetupPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/tickets/page.tsx b/src/app/docs/admin/tickets/page.tsx
new file mode 100644
index 0000000..ba47722
--- /dev/null
+++ b/src/app/docs/admin/tickets/page.tsx
@@ -0,0 +1,5 @@
+import { AdminTicketsDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsTicketsPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/admin/wallet/page.tsx b/src/app/docs/admin/wallet/page.tsx
new file mode 100644
index 0000000..6692e62
--- /dev/null
+++ b/src/app/docs/admin/wallet/page.tsx
@@ -0,0 +1,5 @@
+import { AdminWalletDocScreen } from "@/modules/docs/admin/admin-doc-screens";
+
+export default function AdminDocsWalletPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/integration/admin-guide/page.tsx b/src/app/docs/integration/admin-guide/page.tsx
new file mode 100644
index 0000000..7d59c99
--- /dev/null
+++ b/src/app/docs/integration/admin-guide/page.tsx
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function LegacyAdminGuidePage(): never {
+ redirect("/docs/admin");
+}
diff --git a/src/app/docs/integration/api-reference/page.tsx b/src/app/docs/integration/api-reference/page.tsx
new file mode 100644
index 0000000..6537928
--- /dev/null
+++ b/src/app/docs/integration/api-reference/page.tsx
@@ -0,0 +1,6 @@
+import { redirect } from "next/navigation";
+
+/** 旧链接兼容:完整内容已拆至左侧分章导航 */
+export default function ApiReferencePage(): never {
+ redirect("/docs/integration");
+}
diff --git a/src/app/docs/integration/delivery/page.tsx b/src/app/docs/integration/delivery/page.tsx
new file mode 100644
index 0000000..9477937
--- /dev/null
+++ b/src/app/docs/integration/delivery/page.tsx
@@ -0,0 +1,5 @@
+import { DeliveryDocScreen } from "@/modules/docs/integration/integration-doc-screens";
+
+export default function IntegrationDeliveryPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/integration/troubleshooting/page.tsx b/src/app/docs/integration/troubleshooting/page.tsx
new file mode 100644
index 0000000..d4bae2e
--- /dev/null
+++ b/src/app/docs/integration/troubleshooting/page.tsx
@@ -0,0 +1,5 @@
+import { TroubleshootingDocScreen } from "@/modules/docs/integration/integration-doc-screens";
+
+export default function IntegrationTroubleshootingPage(): React.ReactElement {
+ return
;
+}
diff --git a/src/app/docs/layout.tsx b/src/app/docs/layout.tsx
index 41d5188..8b2e994 100644
--- a/src/app/docs/layout.tsx
+++ b/src/app/docs/layout.tsx
@@ -5,10 +5,10 @@ import { DocsShell } from "@/components/docs/docs-shell";
export const metadata: Metadata = {
title: {
- template: "%s · Integration API",
- default: "Integration API",
+ template: "%s · Docs",
+ default: "Documentation",
},
- description: "Lottery integration docs: SSO, wallet gateway, transfers.",
+ description: "Lottery admin user guide and API integration documentation.",
};
export default function DocsLayout({ children }: { children: ReactNode }): React.ReactElement {
diff --git a/src/app/globals.css b/src/app/globals.css
index 48df7e2..a8a8232 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -238,3 +238,21 @@
}
}
+/* 公开文档站:正文链接与强调,避免继承后台 muted 色 */
+.docs-site .doc-content a:not([class]) {
+ color: #0f172a;
+ font-weight: 500;
+ text-decoration: underline;
+ text-decoration-color: #cbd5e1;
+ text-underline-offset: 2px;
+}
+
+.docs-site .doc-content a:not([class]):hover {
+ text-decoration-color: #64748b;
+}
+
+.docs-site .doc-content strong {
+ color: #0f172a;
+ font-weight: 600;
+}
+
diff --git a/src/components/admin/admin-breadcrumb.tsx b/src/components/admin/admin-breadcrumb.tsx
index 233354e..84e0eba 100644
--- a/src/components/admin/admin-breadcrumb.tsx
+++ b/src/components/admin/admin-breadcrumb.tsx
@@ -41,7 +41,7 @@ const TOP_ROUTE_LABELS: Record
= {
};
const AGENT_ROUTE_LABELS: Record = {
- list: "agents.directoryTitle",
+ list: "agents.listTitle",
provision: "agents.subnav.provision",
"settlement-bills": "settlementCenter.title",
};
diff --git a/src/components/admin/admin-page-guide.tsx b/src/components/admin/admin-page-guide.tsx
new file mode 100644
index 0000000..52a6da5
--- /dev/null
+++ b/src/components/admin/admin-page-guide.tsx
@@ -0,0 +1,37 @@
+"use client";
+
+import Link from "next/link";
+import { BookOpenIcon } from "lucide-react";
+import { useTranslation } from "react-i18next";
+
+import { cn } from "@/lib/utils";
+
+type AdminPageGuideProps = {
+ guide: string;
+ docHref?: string;
+ className?: string;
+};
+
+export function AdminPageGuide({ guide, docHref, className }: AdminPageGuideProps): React.ReactElement {
+ const { t } = useTranslation("common");
+
+ return (
+
+
{guide}
+ {docHref ? (
+
+
+ {t("docs.learnMore")}
+
+ ) : null}
+
+ );
+}
diff --git a/src/components/admin/admin-shell.tsx b/src/components/admin/admin-shell.tsx
index d29a551..365869d 100644
--- a/src/components/admin/admin-shell.tsx
+++ b/src/components/admin/admin-shell.tsx
@@ -48,7 +48,7 @@ export function AdminShell({ children }: { children: ReactNode }) {
)}
-
+
{children}
diff --git a/src/components/admin/module-scaffold.tsx b/src/components/admin/module-scaffold.tsx
index a6d0d08..0d6be69 100644
--- a/src/components/admin/module-scaffold.tsx
+++ b/src/components/admin/module-scaffold.tsx
@@ -15,7 +15,7 @@ export function ModuleScaffold({ children, className, embedded = false }: Module
{t("toolbar.accountSettings")}
+
router.push("/docs/admin")}
+ >
+
+ {t("toolbar.relatedDocs")}
+
diff --git a/src/components/docs/doc-code.tsx b/src/components/docs/doc-code.tsx
index b29a3d7..3622372 100644
--- a/src/components/docs/doc-code.tsx
+++ b/src/components/docs/doc-code.tsx
@@ -9,12 +9,14 @@ type DocCodeProps = {
children: string;
language?: HighlightLang;
className?: string;
+ title?: string;
};
export function DocCode({
children,
language = "json",
className,
+ title,
}: DocCodeProps): React.ReactElement {
const [html, setHtml] = useState(null);
const code = children.trimEnd();
@@ -36,17 +38,22 @@ export function DocCode({
return (
+ {title ? (
+
+ {title}
+
+ ) : null}
{html ? (
) : (
-
+
{code}
)}
diff --git a/src/components/docs/doc-ui.tsx b/src/components/docs/doc-ui.tsx
index 0736512..0cb46eb 100644
--- a/src/components/docs/doc-ui.tsx
+++ b/src/components/docs/doc-ui.tsx
@@ -4,6 +4,11 @@ import { cn } from "@/lib/utils";
export { DocCode } from "@/components/docs/doc-code";
+/** 文档正文容器:统一字号与段落间距 */
+export function DocPage({ children }: { children: ReactNode }): React.ReactElement {
+ return {children};
+}
+
export function DocPageHeader({
title,
description,
@@ -12,10 +17,14 @@ export function DocPageHeader({
description?: string;
}): React.ReactElement {
return (
-
- {title}
+
+
+ {title}
+
{description ? (
- {description}
+
+ {description}
+
) : null}
);
@@ -31,26 +40,39 @@ export function DocSection({
className?: string;
}): React.ReactElement {
return (
-
- {title ? {title}
: null}
+
+ {title ? (
+
+ {title}
+
+ ) : null}
{children}
);
}
+export function DocParagraph({ children }: { children: ReactNode }): React.ReactElement {
+ return {children}
;
+}
+
export function DocNote({ children }: { children: ReactNode }): React.ReactElement {
return (
- {children}
+
);
}
export function DocList({ items }: { items: readonly string[] }): React.ReactElement {
return (
-
+
{items.map((item) => (
- -
- ·
- {item}
+
-
+
+ {item}
))}
@@ -59,9 +81,11 @@ export function DocList({ items }: { items: readonly string[] }): React.ReactEle
export function DocOrderedList({ items }: { items: readonly string[] }): React.ReactElement {
return (
-
+
{items.map((item) => (
- - {item}
+ -
+ {item}
+
))}
);
@@ -77,14 +101,14 @@ export function DocTable({
compact?: boolean;
}): React.ReactElement {
return (
-
-
+
+
-
+
{headers.map((header) => (
|
{header}
|
@@ -93,13 +117,17 @@ export function DocTable({
{rows.map((row, rowIndex) => (
-
+
{row.map((cell, cellIndex) => (
{cell}
@@ -115,15 +143,19 @@ export function DocTable({
export function DocEndpoint({ method, path }: { method: string; path: string }): React.ReactElement {
return (
-
- {method}
- {path}
+
+
+ {method}
+
+ {path}
);
}
export function DocInlineCode({ children }: { children: ReactNode }): React.ReactElement {
return (
- {children}
+
+ {children}
+
);
}
diff --git a/src/components/docs/docs-admin-console-link.tsx b/src/components/docs/docs-admin-console-link.tsx
new file mode 100644
index 0000000..5355cc7
--- /dev/null
+++ b/src/components/docs/docs-admin-console-link.tsx
@@ -0,0 +1,31 @@
+"use client";
+
+import Link from "next/link";
+import { useTranslation } from "react-i18next";
+
+import { cn } from "@/lib/utils";
+
+type DocsAdminConsoleLinkProps = {
+ namespace: "adminDocs" | "integrationDocs";
+ className?: string;
+};
+
+export function DocsAdminConsoleLink({
+ namespace,
+ className,
+}: DocsAdminConsoleLinkProps): React.ReactElement {
+ const { t } = useTranslation(namespace);
+ const label = t("shell.adminLogin");
+
+ return (
+
+ {label}
+
+ );
+}
diff --git a/src/components/docs/docs-shell.tsx b/src/components/docs/docs-shell.tsx
index 209ba6c..46d16cb 100644
--- a/src/components/docs/docs-shell.tsx
+++ b/src/components/docs/docs-shell.tsx
@@ -1,9 +1,12 @@
"use client";
import Link from "next/link";
+import { usePathname } from "next/navigation";
import { useTranslation } from "react-i18next";
import { AdminLanguageSwitcher } from "@/components/admin/admin-language-switcher";
+import { DocsAdminConsoleLink } from "@/components/docs/docs-admin-console-link";
+import { DocsTopNav } from "@/components/docs/docs-top-nav";
import { cn } from "@/lib/utils";
type DocsShellProps = {
@@ -12,23 +15,28 @@ type DocsShellProps = {
};
export function DocsShell({ children, className }: DocsShellProps): React.ReactElement {
- const { t } = useTranslation("integrationDocs");
+ const pathname = usePathname();
+ const isAdminDocs = pathname === "/docs/admin" || pathname.startsWith("/docs/admin/");
+ const namespace = isAdminDocs ? "adminDocs" : "integrationDocs";
+ const homeHref = isAdminDocs ? "/docs/admin" : "/docs/integration";
+ const { t } = useTranslation(namespace);
return (
-
-
-
-
- {t("shell.title")}
-
-
-
+
+
@@ -45,9 +53,11 @@ export function DocsBody({
children: React.ReactNode;
}): React.ReactElement {
return (
-
+
{sidebar}
- {children}
+
+ {children}
+
);
}
diff --git a/src/components/docs/docs-sidebar.tsx b/src/components/docs/docs-sidebar.tsx
index fddbc66..ddff37c 100644
--- a/src/components/docs/docs-sidebar.tsx
+++ b/src/components/docs/docs-sidebar.tsx
@@ -8,43 +8,49 @@ import type { DocsNavGroup } from "@/lib/docs-nav";
import { resolveDocsNavLabel } from "@/lib/docs-nav-labels";
import { cn } from "@/lib/utils";
-export function DocsSidebar({ groups }: { groups: readonly DocsNavGroup[] }): React.ReactElement {
+export function DocsSidebar({
+ groups,
+ namespace = "integrationDocs",
+}: {
+ groups: readonly DocsNavGroup[];
+ namespace?: "integrationDocs" | "adminDocs";
+}): React.ReactElement {
const pathname = usePathname();
- const { t, i18n } = useTranslation("integrationDocs");
+ const { t, i18n } = useTranslation(namespace);
+
+ const homeHref = namespace === "adminDocs" ? "/docs/admin" : "/docs/integration";
const label = (key: string): string => {
const translated = t(key);
if (translated !== key) {
return translated;
}
- return resolveDocsNavLabel(key, i18n.resolvedLanguage ?? i18n.language);
+ return resolveDocsNavLabel(key, i18n.resolvedLanguage ?? i18n.language, namespace);
};
return (
- |