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}
|
||||
refreshing={refreshing}
|
||||
onRefresh={refresh}
|
||||
onOpenApi={() => navigate('/interface')}
|
||||
/>
|
||||
)}
|
||||
{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
|
||||
refreshing: boolean
|
||||
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
|
||||
|
||||
return (
|
||||
@@ -56,7 +64,16 @@ export function ServicePanel({ projects, live, refreshing, onRefresh }: ServiceP
|
||||
重新扫描
|
||||
</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" />
|
||||
查看接口
|
||||
</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