From 13840754ad5ac87923dc9c7b314f95edccff3aa6 Mon Sep 17 00:00:00 2001
From: yun-zhi-ztl <15071461069@163.com>
Date: Sun, 15 Mar 2026 13:44:07 +0800
Subject: [PATCH] feat(dashboard): add back navigation for subpages
---
web/src/i18n/locales/en.json | 1 +
web/src/i18n/locales/zh.json | 1 +
web/src/pages/dashboard/my-namespaces.tsx | 13 ++++----
web/src/pages/dashboard/my-skills.tsx | 17 +++++-----
web/src/pages/dashboard/namespace-members.tsx | 8 +++--
web/src/pages/dashboard/namespace-reviews.tsx | 11 +++----
web/src/pages/dashboard/promotions.tsx | 6 ++--
web/src/pages/dashboard/publish.tsx | 6 ++--
web/src/pages/dashboard/reviews.tsx | 6 ++--
web/src/pages/dashboard/stars.tsx | 6 ++--
web/src/pages/dashboard/tokens.tsx | 9 +++---
.../components/dashboard-page-header.tsx | 31 +++++++++++++++++++
12 files changed, 72 insertions(+), 43 deletions(-)
create mode 100644 web/src/shared/components/dashboard-page-header.tsx
diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index b75ff53f..00f553c9 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -172,6 +172,7 @@
"dashboard": {
"title": "Dashboard",
"subtitle": "Manage your account and API Tokens",
+ "backToDashboard": "Back to Dashboard",
"userInfo": "User Info",
"userInfoDesc": "Your account details",
"loginVia": "Logged in via {{provider}}",
diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json
index 1f5eee18..2abbb441 100644
--- a/web/src/i18n/locales/zh.json
+++ b/web/src/i18n/locales/zh.json
@@ -172,6 +172,7 @@
"dashboard": {
"title": "Dashboard",
"subtitle": "管理你的账户和 API Tokens",
+ "backToDashboard": "返回控制台",
"userInfo": "用户信息",
"userInfoDesc": "你的账户详情",
"loginVia": "通过 {{provider}} 登录",
diff --git a/web/src/pages/dashboard/my-namespaces.tsx b/web/src/pages/dashboard/my-namespaces.tsx
index 46210b30..b7641c26 100644
--- a/web/src/pages/dashboard/my-namespaces.tsx
+++ b/web/src/pages/dashboard/my-namespaces.tsx
@@ -4,6 +4,7 @@ import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
import { NamespaceBadge } from '@/shared/components/namespace-badge'
import { EmptyState } from '@/shared/components/empty-state'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { useMyNamespaces } from '@/shared/hooks/use-skill-queries'
export function MyNamespacesPage() {
@@ -37,13 +38,11 @@ export function MyNamespacesPage() {
return (
-
-
-
{t('myNamespaces.title')}
-
{t('myNamespaces.subtitle')}
-
-
-
+
{t('myNamespaces.create')}}
+ />
{namespaces && namespaces.length > 0 ? (
diff --git a/web/src/pages/dashboard/my-skills.tsx b/web/src/pages/dashboard/my-skills.tsx
index 1278858a..5a94b3d4 100644
--- a/web/src/pages/dashboard/my-skills.tsx
+++ b/web/src/pages/dashboard/my-skills.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
import { EmptyState } from '@/shared/components/empty-state'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { useMySkills } from '@/shared/hooks/use-skill-queries'
import { formatCompactCount } from '@/shared/lib/number-format'
@@ -47,15 +48,15 @@ export function MySkillsPage() {
return (
-
-
-
{t('mySkills.title')}
-
{t('mySkills.subtitle')}
-
-
-
+
+ )}
+ />
{skills && skills.length > 0 ? (
diff --git a/web/src/pages/dashboard/namespace-members.tsx b/web/src/pages/dashboard/namespace-members.tsx
index 6081a7f1..b7af1374 100644
--- a/web/src/pages/dashboard/namespace-members.tsx
+++ b/web/src/pages/dashboard/namespace-members.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { NamespaceHeader } from '@/features/namespace/namespace-header'
import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { useNamespaceDetail, useNamespaceMembers } from '@/shared/hooks/use-skill-queries'
export function NamespaceMembersPage() {
@@ -34,11 +35,14 @@ export function NamespaceMembersPage() {
return (
+
-
-
{t('members.title')}
+
diff --git a/web/src/pages/dashboard/namespace-reviews.tsx b/web/src/pages/dashboard/namespace-reviews.tsx
index 250e8471..16f4cf7a 100644
--- a/web/src/pages/dashboard/namespace-reviews.tsx
+++ b/web/src/pages/dashboard/namespace-reviews.tsx
@@ -4,6 +4,7 @@ import { Card } from '@/shared/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
import { useNamespaceDetail } from '@/shared/hooks/use-skill-queries'
import { useReviewList } from '@/features/review/use-review-list'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
function ReviewListSection({ namespaceId }: { namespaceId?: number }) {
const { t } = useTranslation()
@@ -56,12 +57,10 @@ export function NamespaceReviewsPage() {
return (
-
-
{t('nsReviews.title')}
-
- {namespace ? t('nsReviews.reviewsFor', { name: namespace.displayName }) : t('nsReviews.loadingNamespace')}
-
-
+
)
diff --git a/web/src/pages/dashboard/promotions.tsx b/web/src/pages/dashboard/promotions.tsx
index 446ad898..d3a2e5d5 100644
--- a/web/src/pages/dashboard/promotions.tsx
+++ b/web/src/pages/dashboard/promotions.tsx
@@ -5,6 +5,7 @@ import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
import { Input } from '@/shared/ui/input'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
function PromotionSection({ status }: { status: 'PENDING' | 'APPROVED' | 'REJECTED' }) {
const { t, i18n } = useTranslation()
@@ -70,10 +71,7 @@ export function PromotionsPage() {
const { t } = useTranslation()
return (
-
-
{t('promotions.title')}
-
{t('promotions.subtitle')}
-
+
{t('promotions.tabPending')}
diff --git a/web/src/pages/dashboard/publish.tsx b/web/src/pages/dashboard/publish.tsx
index b3ee3790..febfb8e0 100644
--- a/web/src/pages/dashboard/publish.tsx
+++ b/web/src/pages/dashboard/publish.tsx
@@ -7,6 +7,7 @@ import { Select } from '@/shared/ui/select'
import { Label } from '@/shared/ui/label'
import { Card } from '@/shared/ui/card'
import { useMyNamespaces, usePublishSkill } from '@/shared/hooks/use-skill-queries'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { toast } from '@/shared/lib/toast'
import { ApiError } from '@/api/client'
@@ -73,10 +74,7 @@ export function PublishPage() {
return (
-
-
{t('publish.title')}
-
{t('publish.subtitle')}
-
+
diff --git a/web/src/pages/dashboard/reviews.tsx b/web/src/pages/dashboard/reviews.tsx
index 5ce4225b..da5b9fc5 100644
--- a/web/src/pages/dashboard/reviews.tsx
+++ b/web/src/pages/dashboard/reviews.tsx
@@ -11,6 +11,7 @@ import {
TableRow,
} from '@/shared/ui/table'
import { useReviewList } from '@/features/review/use-review-list'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
export function ReviewsPage() {
const { t, i18n } = useTranslation()
@@ -94,10 +95,7 @@ export function ReviewsPage() {
return (
-
-
{t('reviews.title')}
-
{t('reviews.subtitle')}
-
+
diff --git a/web/src/pages/dashboard/stars.tsx b/web/src/pages/dashboard/stars.tsx
index 5a570dc1..7e0e59f5 100644
--- a/web/src/pages/dashboard/stars.tsx
+++ b/web/src/pages/dashboard/stars.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { SkillCard } from '@/features/skill/skill-card'
import { useMyStars } from '@/shared/hooks/use-skill-queries'
import { Card } from '@/shared/ui/card'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
export function MyStarsPage() {
const { t } = useTranslation()
@@ -21,10 +22,7 @@ export function MyStarsPage() {
return (
-
-
{t('stars.title')}
-
{t('stars.subtitle')}
-
+
{!skills || skills.length === 0 ? (
{t('stars.empty')}
diff --git a/web/src/pages/dashboard/tokens.tsx b/web/src/pages/dashboard/tokens.tsx
index 034e0f96..5f8a478e 100644
--- a/web/src/pages/dashboard/tokens.tsx
+++ b/web/src/pages/dashboard/tokens.tsx
@@ -1,14 +1,15 @@
import { useTranslation } from 'react-i18next'
import { TokenList } from '@/features/token/token-list'
+import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
export function TokensPage() {
const { t } = useTranslation()
return (
-
-
{t('tokens.pageTitle')}
-
{t('tokens.pageSubtitle')}
-
+
)
diff --git a/web/src/shared/components/dashboard-page-header.tsx b/web/src/shared/components/dashboard-page-header.tsx
new file mode 100644
index 00000000..33715403
--- /dev/null
+++ b/web/src/shared/components/dashboard-page-header.tsx
@@ -0,0 +1,31 @@
+import { useNavigate } from '@tanstack/react-router'
+import { ArrowLeft } from 'lucide-react'
+import { useTranslation } from 'react-i18next'
+import { Button } from '@/shared/ui/button'
+
+interface DashboardPageHeaderProps {
+ title: string
+ subtitle?: string
+ actions?: React.ReactNode
+}
+
+export function DashboardPageHeader({ title, subtitle, actions }: DashboardPageHeaderProps) {
+ const { t } = useTranslation()
+ const navigate = useNavigate()
+
+ return (
+
+
+
+
+
{title}
+ {subtitle ?
{subtitle}
: null}
+
+ {actions}
+
+
+ )
+}