- 页头中间信息改为无缝滚动 ticker(3 份拼接,24s 线性,尊重 reduced-motion) - 去掉分区 / 条目 / 文章三处「返回」「返回首页」按钮 - 面包屑移到左侧,中间项可点击并通过 onNavigate 走 SPA 路由 - 侧栏新增「首页」,首页时高亮,点击回首页
131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
import {
|
|
Breadcrumb,
|
|
Card,
|
|
Icon,
|
|
IconButton,
|
|
Paragraph,
|
|
Space,
|
|
Tag,
|
|
Text,
|
|
Title,
|
|
type BreadcrumbItem,
|
|
} from '@stash/ui'
|
|
import type { ItemDetailModel } from '../../data/detail'
|
|
import type { RelatedItem } from '../../data/types'
|
|
import { RelatedList } from './RelatedList'
|
|
|
|
/**
|
|
* 条目详情页:应用与电影共用。
|
|
*
|
|
* 版式:面包屑 + 标题 + 主图(方形头像 / 竖版海报)+ 标签行 + 一句话评价 + 正文
|
|
* + 操作条(浏览 / 点赞 / 分享 / 跳转)+ 可选横幅 + 「推荐阅读」。
|
|
* 具体形态由 ItemDetailModel 决定,这里不判断条目类型。
|
|
*/
|
|
type ItemDetailViewProps = {
|
|
crumbs: BreadcrumbItem[]
|
|
model: ItemDetailModel
|
|
related: RelatedItem[]
|
|
onNavigate: (href: string) => void
|
|
onOpenItem: (itemId: string) => void
|
|
}
|
|
|
|
export function ItemDetailView({
|
|
crumbs,
|
|
model,
|
|
related,
|
|
onNavigate,
|
|
onOpenItem,
|
|
}: ItemDetailViewProps) {
|
|
return (
|
|
<div className="detail-view item-view">
|
|
<Card padding="none" className="detail-nav">
|
|
<Breadcrumb className="detail-breadcrumb" items={crumbs} onNavigate={onNavigate} />
|
|
</Card>
|
|
|
|
<Card padding="none" className="item-card">
|
|
<Title level={1} as="h2" weight="semibold" className="item-title">
|
|
{model.title}
|
|
<button type="button" className="item-edit" disabled title="编辑功能待接入">
|
|
[编辑]
|
|
</button>
|
|
</Title>
|
|
|
|
<div className={`item-cover item-cover--${model.shape}`}>
|
|
{model.cover !== undefined ? (
|
|
<img src={model.cover} alt={model.title} loading="lazy" />
|
|
) : (
|
|
<span className="item-cover-letter">{model.fallbackIcon ?? '•'}</span>
|
|
)}
|
|
</div>
|
|
|
|
{model.tags.length > 0 && (
|
|
<Space gap="sm" wrap>
|
|
{model.tags.map((tag) => (
|
|
<Tag key={tag} tone="primary" className="item-tag">
|
|
{tag}
|
|
</Tag>
|
|
))}
|
|
</Space>
|
|
)}
|
|
|
|
{model.comment !== undefined && (
|
|
<p className="item-quote">
|
|
<span className="item-quote-mark" aria-hidden="true">
|
|
“
|
|
</span>
|
|
<span className="item-quote-text">{model.comment}</span>
|
|
</p>
|
|
)}
|
|
|
|
{model.paragraphs.map((paragraph, index) => (
|
|
<Paragraph
|
|
key={`${index}-${paragraph.slice(0, 8)}`}
|
|
tone="sub"
|
|
size="md"
|
|
className="item-desc"
|
|
>
|
|
{paragraph}
|
|
</Paragraph>
|
|
))}
|
|
|
|
<div className="item-actions">
|
|
<Space gap="sm">
|
|
<Space gap="xs" className="item-stat">
|
|
<Icon name="eye_line" />
|
|
<Text size="xs" tone="sub">
|
|
{model.views}
|
|
</Text>
|
|
</Space>
|
|
<Space gap="xs" className="item-stat">
|
|
<Icon name="thumb_up_2_line" />
|
|
<Text size="xs" tone="sub">
|
|
{model.likes}
|
|
</Text>
|
|
</Space>
|
|
<IconButton label="分享(待接入)" size="sm" icon={<Icon name="share_3_line" />} />
|
|
</Space>
|
|
|
|
{/* 占位数据没有真实地址时,按钮置灰而不是打开空白页 */}
|
|
{model.href === '#' ? (
|
|
<button type="button" className="item-jump" disabled title="暂无跳转地址">
|
|
跳转到
|
|
<Icon name="a-external_link_line1" />
|
|
</button>
|
|
) : (
|
|
<a className="item-jump" href={model.href} target="_blank" rel="noreferrer">
|
|
跳转到
|
|
<Icon name="a-external_link_line1" />
|
|
</a>
|
|
)}
|
|
</div>
|
|
|
|
{model.banner !== undefined && (
|
|
<img className="item-banner" src={model.banner} alt="" loading="lazy" />
|
|
)}
|
|
</Card>
|
|
|
|
<RelatedList items={related} onOpen={onOpenItem} />
|
|
</div>
|
|
)
|
|
}
|