import { categoryCount, flattenAppItems, type Category } from '../../data/types' import { AppGrid } from './AppGrid' import { ArticleGrid } from './ArticleGrid' import { Empty } from '@stash/ui' import { PosterGrid } from './PosterGrid' import { SectionCard } from './SectionCard' import { applySectionSettings, sectionLimit, sectionTitle, type SectionSettings, } from '../../settings' /** * 首页:把每个分类渲染成一张分区卡片。 * * 每个分区只展示前若干条;标题、条数、顺序与显隐都可以在 `/admin` * 的「首页卡片」里覆盖(见 settings.sections)。 */ type HomeViewProps = { categories: Category[] sections: SectionSettings onOpenDetail: (categoryId: string) => void onOpenItem: (categoryId: string, itemId: string) => void } export function HomeView({ categories, sections, onOpenDetail, onOpenItem }: HomeViewProps) { const cards = applySectionSettings(categories, sections) return (
{cards.map((category) => ( onOpenDetail(category.id)} > {renderPreview(category, sections, onOpenItem)} ))}
) } /** * 卡片右上角的数量角标。 * * 配了「分组展示块」时,卡片实际展示的是那个分组,所以数量也应该只数它; * 否则(电影 / 文章 / 本地服务)数整个分区。 */ function cardCount(category: Category): number { if (category.block !== undefined) { const group = category.groups.find((item) => item.id === category.block?.nodeKey) if (group !== undefined) return group.items.length } return categoryCount(category) } /** 某个分区配的「首页预览分组」;没配或找不到返回 undefined */ function blockGroup(category: { block?: { nodeKey?: string }; groups: { id: string; items: T[] }[] }) { if (category.block?.nodeKey === undefined) return undefined return category.groups.find((group) => group.id === category.block?.nodeKey) } /** 按分类类型输出对应的预览网格;应用类为空时给出提示文案 */ function renderPreview( category: Category, sections: SectionSettings, onOpenItem: (categoryId: string, itemId: string) => void, ) { if (category.kind === 'apps') { // 配了展示块且指向分组时只展示该组;展示块指向分区本身(「整个分区」)时展示全部条目 const group = blockGroup(category) const source = group !== undefined ? group.items : flattenAppItems(category) const fallback = category.block?.previewLimit ?? category.previewLimit ?? 4 const limit = sectionLimit(category.id, fallback, sections) const items = source.slice(0, limit) if (items.length === 0) { return } return onOpenItem(category.id, itemId)} /> } if (category.kind === 'posters') { const group = blockGroup(category) const source = group ? group.items : [...category.items, ...category.groups.flatMap((item) => item.items)] return ( onOpenItem(category.id, itemId)} /> ) } const group = blockGroup(category) const source = group ? group.items : [...category.items, ...category.groups.flatMap((item) => item.items)] return ( onOpenItem(category.id, itemId)} /> ) }