feat: 「查看接口」改为站内路由,只换右侧内容
- ServicePanel 新增 onOpenApi,链接点击接管为 navigate('/interface');
按住 Ctrl/Cmd/Shift/Alt 仍保留新标签打开
- 前台内容区已有 route.kind === 'api' 分支,直接渲染接口一览
- 顺手删掉两个没人引用的旧组件:sidebar/Sidebar.tsx、sidebar/CategoryNav.tsx
This commit is contained in:
@@ -710,6 +710,7 @@ export default function AppNext() {
|
|||||||
live={live}
|
live={live}
|
||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
onRefresh={refresh}
|
onRefresh={refresh}
|
||||||
|
onOpenApi={() => navigate('/interface')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{site.sidebar.show_nav !== false && (
|
{site.sidebar.show_nav !== false && (
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
import { Card, Menu, type MenuItem } from '@stash/ui'
|
|
||||||
import type { NavTarget } from '../../data/nav'
|
|
||||||
import type { Category } from '../../data/types'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分类导航树:由内容树派生。
|
|
||||||
*
|
|
||||||
* - 有分组的分类(apps)是折叠节点,子项是分组(分组可用 show_in_sidebar 单独隐藏);
|
|
||||||
* - 没有分组、或分组全被隐藏的分类,就是一个普通菜单项。
|
|
||||||
*
|
|
||||||
* 折叠状态由组件库的 Menu 内部维护;这里只负责把内容树翻译成 items。
|
|
||||||
*/
|
|
||||||
type CategoryNavProps = {
|
|
||||||
/** 内容目录;顺序即侧栏顺序 */
|
|
||||||
categories: Category[]
|
|
||||||
/** 当前明细视图的分类 / 分组,用于高亮 */
|
|
||||||
activeCategoryId?: string
|
|
||||||
activeGroupId?: string
|
|
||||||
/** 是否在首页(高亮「首页」项) */
|
|
||||||
homeActive?: boolean
|
|
||||||
onNavigate: (target: NavTarget) => void
|
|
||||||
/** 点击「首页」 */
|
|
||||||
onHome: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const HOME_KEY = 'home'
|
|
||||||
const categoryKey = (id: string) => `cat:${id}`
|
|
||||||
const groupKey = (categoryId: string, groupId: string) => `group:${categoryId}:${groupId}`
|
|
||||||
|
|
||||||
export function CategoryNav({
|
|
||||||
categories,
|
|
||||||
activeCategoryId,
|
|
||||||
activeGroupId,
|
|
||||||
homeActive = false,
|
|
||||||
onNavigate,
|
|
||||||
onHome,
|
|
||||||
}: CategoryNavProps) {
|
|
||||||
const items: MenuItem[] = [
|
|
||||||
{ key: HOME_KEY, label: '首页' },
|
|
||||||
...categories.map((category) => {
|
|
||||||
// 「允许子分组」的分区才有 groups;空分组不出现在侧栏(后台仍保留)
|
|
||||||
const groups = category.groups.filter((group) => group.items.length > 0)
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: categoryKey(category.id),
|
|
||||||
label: category.title,
|
|
||||||
children:
|
|
||||||
groups.length > 0
|
|
||||||
? groups.map((group) => ({
|
|
||||||
key: groupKey(category.id, group.id),
|
|
||||||
label: group.name,
|
|
||||||
}))
|
|
||||||
: undefined,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
const activeKey = homeActive
|
|
||||||
? HOME_KEY
|
|
||||||
: activeCategoryId === undefined
|
|
||||||
? undefined
|
|
||||||
: activeGroupId !== undefined
|
|
||||||
? groupKey(activeCategoryId, activeGroupId)
|
|
||||||
: categoryKey(activeCategoryId)
|
|
||||||
|
|
||||||
const handleSelect = (key: string) => {
|
|
||||||
if (key === HOME_KEY) {
|
|
||||||
onHome()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.startsWith('group:')) {
|
|
||||||
const [, categoryId, groupId] = key.split(':')
|
|
||||||
onNavigate({ categoryId, groupId })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
onNavigate({ categoryId: key.slice('cat:'.length) })
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card padding="none" className="nav-card">
|
|
||||||
<Menu items={items} activeKey={activeKey} onSelect={handleSelect} itemHeight={39} />
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -10,9 +10,17 @@ type ServicePanelProps = {
|
|||||||
live: boolean
|
live: boolean
|
||||||
refreshing: boolean
|
refreshing: boolean
|
||||||
onRefresh: () => void
|
onRefresh: () => void
|
||||||
|
/** 打开接口一览:走站内路由,不整页刷新 */
|
||||||
|
onOpenApi: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ServicePanel({ projects, live, refreshing, onRefresh }: ServicePanelProps) {
|
export function ServicePanel({
|
||||||
|
projects,
|
||||||
|
live,
|
||||||
|
refreshing,
|
||||||
|
onRefresh,
|
||||||
|
onOpenApi,
|
||||||
|
}: ServicePanelProps) {
|
||||||
const host = typeof window === 'undefined' ? '-' : window.location.host
|
const host = typeof window === 'undefined' ? '-' : window.location.host
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -56,7 +64,16 @@ export function ServicePanel({ projects, live, refreshing, onRefresh }: ServiceP
|
|||||||
重新扫描
|
重新扫描
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<a className="link-button" href="/interface">
|
<a
|
||||||
|
className="link-button"
|
||||||
|
href="/interface"
|
||||||
|
onClick={(event) => {
|
||||||
|
// 无修饰键时接管点击,走站内路由,只换右侧内容;按住修饰键仍可新标签打开
|
||||||
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return
|
||||||
|
event.preventDefault()
|
||||||
|
onOpenApi()
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Icon name="link_3_line" />
|
<Icon name="link_3_line" />
|
||||||
查看接口
|
查看接口
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import type { Project } from '../../api'
|
|
||||||
import type { NavTarget } from '../../data/nav'
|
|
||||||
import type { Category } from '../../data/types'
|
|
||||||
import type { ProfileSettings } from '../../settings'
|
|
||||||
import { CategoryNav } from './CategoryNav'
|
|
||||||
import { ProfileCard } from './ProfileCard'
|
|
||||||
import { ServicePanel } from './ServicePanel'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 左侧栏容器:用户资料 + 本地服务面板 + 分类导航。
|
|
||||||
* 只负责布局与数据透传,具体内容由三个子组件分别渲染。
|
|
||||||
*/
|
|
||||||
type SidebarProps = {
|
|
||||||
projects: Project[]
|
|
||||||
/** 内容目录;侧栏直接由它派生 */
|
|
||||||
categories: Category[]
|
|
||||||
profile: ProfileSettings
|
|
||||||
live: boolean
|
|
||||||
refreshing: boolean
|
|
||||||
onRefresh: () => void
|
|
||||||
activeCategoryId?: string
|
|
||||||
activeGroupId?: string
|
|
||||||
/** 是否在首页 */
|
|
||||||
homeActive?: boolean
|
|
||||||
onNavigate: (target: NavTarget) => void
|
|
||||||
/** 点击「首页」 */
|
|
||||||
onHome: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Sidebar({
|
|
||||||
projects,
|
|
||||||
categories,
|
|
||||||
profile,
|
|
||||||
live,
|
|
||||||
refreshing,
|
|
||||||
onRefresh,
|
|
||||||
activeCategoryId,
|
|
||||||
activeGroupId,
|
|
||||||
homeActive = false,
|
|
||||||
onNavigate,
|
|
||||||
onHome,
|
|
||||||
}: SidebarProps) {
|
|
||||||
return (
|
|
||||||
<div className="sidebar">
|
|
||||||
<ProfileCard profile={profile} />
|
|
||||||
|
|
||||||
<ServicePanel
|
|
||||||
projects={projects}
|
|
||||||
live={live}
|
|
||||||
refreshing={refreshing}
|
|
||||||
onRefresh={onRefresh}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CategoryNav
|
|
||||||
categories={categories}
|
|
||||||
activeCategoryId={activeCategoryId}
|
|
||||||
activeGroupId={activeGroupId}
|
|
||||||
homeActive={homeActive}
|
|
||||||
onNavigate={onNavigate}
|
|
||||||
onHome={onHome}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user