import { categoryCount, flattenAppItems, type Category } from '../../data/types' import { AppGrid } from './AppGrid' import { ArticleGrid } from './ArticleGrid' import { PosterGrid } from './PosterGrid' import { SectionCard } from './SectionCard' /** * 首页:把每个分类渲染成一张分区卡片。 * * 每个分区只展示前若干条(由分类的 previewLimit 决定), * 右上角 ••• 进入该分类明细,点击卡片 / 海报则进入该条目的详情。 */ type HomeViewProps = { categories: Category[] onOpenDetail: (categoryId: string) => void onOpenItem: (categoryId: string, itemId: string) => void } export function HomeView({ categories, onOpenDetail, onOpenItem }: HomeViewProps) { return (
{categories.map((category) => ( onOpenDetail(category.id)} > {renderPreview(category, onOpenItem)} ))}
) } /** * 卡片右上角的数量角标。 * * 配了「分组展示块」时,卡片实际展示的是那个分组,所以数量也应该只数它; * 否则(电影 / 文章 / 本地服务)数整个分区。 */ function cardCount(category: Category): number { if (category.kind === 'apps' && category.block !== undefined) { const group = category.groups.find((item) => item.id === category.block?.nodeKey) if (group !== undefined) return group.items.length } return categoryCount(category) } /** 按分类类型输出对应的预览网格;应用类为空时给出提示文案 */ function renderPreview( category: Category, onOpenItem: (categoryId: string, itemId: string) => void, ) { if (category.kind === 'apps') { // 配了展示块就只展示那个分组;没有配置(如「本地服务」)则退回全部条目 const blockGroup = category.block !== undefined ? category.groups.find((group) => group.id === category.block?.nodeKey) : undefined const source = category.block !== undefined ? (blockGroup?.items ?? []) : flattenAppItems(category) const limit = category.block?.previewLimit ?? category.previewLimit ?? 4 const items = source.slice(0, limit) if (items.length === 0) { return

{category.emptyText ?? '暂无内容'}

} return onOpenItem(category.id, itemId)} /> } if (category.kind === 'posters') { return ( onOpenItem(category.id, itemId)} /> ) } return ( onOpenItem(category.id, itemId)} /> ) }