feat: 侧栏卡片显隐、本地服务卡片恢复、页面同步滚动

- 侧边栏设置新增「侧栏卡片」:本地管理员/本地服务显隐,即时保存 show_profile/show_service
- 首页固定第一位恢复「本地服务」卡片(运行时项目网格),移除卡片三点菜单
- 后台首页卡片新增只读「本地服务」表,标记不可删除
- 前台改为整页滚动,左右两栏同步
- 验证:显隐落库、三点为 0、本地表无删除、滚动两栏同步 300px
This commit is contained in:
2026-10-31 14:59:41 +08:00
parent 11f992cdad
commit 0e6c772466
8 changed files with 208 additions and 19 deletions
+36 -11
View File
@@ -208,6 +208,8 @@ export default function AppNext() {
const site: SiteSettings = settings?.settings ?? {
header: { enabled: true, speed: 24, items: [] },
sidebar: {
show_profile: true,
show_service: true,
hidden: [],
order: [],
hidden_groups: [],
@@ -309,6 +311,30 @@ export default function AppNext() {
)
}
function renderLocalService() {
const items: AppItem[] = projects.map((project) => ({
id: project.name,
name: project.name,
desc: project.route_path,
icon: project.name.slice(0, 1).toUpperCase(),
href: project.route_path,
badge: '本地项目',
comment: '本地静态站点,由 Stash 直接托管。',
views: 0,
likes: 0,
}))
return (
<SectionCard title="本地服务" count={items.length} barColor="#3858f6">
{items.length > 0 ? (
<AppGrid items={items} />
) : (
<Empty text="还没有项目:在托管目录下建一个子目录并放入 index.html,刷新后就会出现在这里。" />
)}
</SectionCard>
)
}
function renderCard(card: CardItem) {
const resolved = card.groups
.map((ref) => ({ ref, group: findGroup(manage.groups, ref.groupKey) }))
@@ -327,7 +353,6 @@ export default function AppNext() {
title={card.title}
count={total}
barColor={first?.barColor}
onMore={() => first !== undefined && navigate(`/g/${encodeURIComponent(first.key)}`)}
>
{resolved.map(({ group, ref }) =>
renderGroupBlock(group, ref.previewLimit ?? defaultLimit(group), resolved.length > 1),
@@ -342,6 +367,7 @@ export default function AppNext() {
<div className="home-view">
{loading && <Empty text="正在读取内容库…" />}
{!loading && cards.length === 0 && <Empty text="后台还没有创建首页卡片" />}
{renderLocalService()}
{cards.map(renderCard)}
{keywordLower !== '' && cards.length > 0 && (
<Notice title={`搜索结果:${keyword.trim()}`}>在卡片与分组内按标题过滤。</Notice>
@@ -521,9 +547,6 @@ export default function AppNext() {
siderBordered={false}
contentPadding="none"
contentOffset={88}
height="screen"
scrollable
hideScrollbar
contentId="content-scroll"
className="app"
header={
@@ -546,13 +569,15 @@ export default function AppNext() {
}
sider={
<div className="sidebar">
<ProfileCard profile={site.profile} />
<ServicePanel
projects={projects}
live={live}
refreshing={refreshing}
onRefresh={refresh}
/>
{site.sidebar.show_profile !== false && <ProfileCard profile={site.profile} />}
{site.sidebar.show_service !== false && (
<ServicePanel
projects={projects}
live={live}
refreshing={refreshing}
onRefresh={refresh}
/>
)}
<div className="nav-card">
<Menu
items={sidebarItems}