Files
newsui/HANDOFF.md
T

643 lines
30 KiB
Markdown
Raw Normal View History

# NewspaperUI 交接文档
## 当前完成进度
### ✅ 已完成
1. **Stage 1**theme + utils 基础设施重写
2. **Stage 2**:18 个组件全部重写(Layout / Section / Article / Layer / Masthead / Rule / Headline / Subhead / Kicker / BodyText / Quote / Byline / Dateline / Caption / Image / Figure / Video / PullQuote
3. **Stage 3**:生产级头版 demoNYT + Blackletter
4. **Stage 4**9 个文档章节
5. **Stage 5**:验证(29/29 测试通过,Design Agent 复评 9/10
6. **同步 design.md**
7. **#17**:修复首页 + Blackletter 头版的空白问题(Briefs 增加新闻条目,BodyText 增加段落)
8. **#18**:修复 TypeScript lint warnings(重新 build 生成 .d.ts
9. **#16**Landing Page + Header 重构
- 新建 `packages/docs/components/Header.tsx`(全局 sticky Header,包含 Docs/Components/Themes/Blocks/GitHub 导航)
- 重写 `packages/docs/app/layout.tsx` 引入 Header
- 调整 `packages/docs/app/(docs)/layout.tsx` 适配 Header 高度(65px
- 调整 `packages/docs/components/Sidebar.tsx` sticky `top: 65px`
- **NYT 头版迁移到 `/examples/nyt-frontpage`**
- 新建 `packages/docs/app/page.tsx` 作为报纸风格 Landing Page,使用 Masthead + 7 个 demo 卡片垂直分布
### ⏳ 未完成
10. **#15**Blocks 页面 6 个完整 demo**核心剩余工作**)
11. **#13**Stage 6 — JSDoc + README
---
## 系统现状
### Monorepo 结构
```
/Users/joi-com/Desktop/space/newspaperui
├── packages/
│ ├── theme/ # CSS variables + 视觉权重表 + 字体 + 排版工具类
│ ├── utils/ # validateSpan / clampSpan / cx
│ ├── components/ # 18 个 React 组件
│ └── docs/ # Next.js 15 文档站
├── design.md # 设计规范(已同步修订版)
├── HANDOFF.md # 本文档
└── SKILL.md # 工作流方法论
```
### 工具链版本
- pnpm workspace + Turborepo
- React 18.3 / TypeScript 5.7 / Next.js 15.5 / Vite 5.4 / Tailwind 3.4
- Vitest + React Testing Library
### 关键命令
```bash
cd /Users/joi-com/Desktop/space/newspaperui
# 全量构建
pnpm build
# 测试
pnpm --filter @newspaperui/utils test # 11 tests
pnpm --filter @newspaperui/components test # 18 tests
# 开发服务器
pnpm --filter @newspaperui/docs dev # http://localhost:3000
```
### 已通过验证
- `pnpm build` 4 packages 全部通过,0 warning
- `pnpm test` 29/29 通过
- Playwright 实测 13 项视觉清单全 PASS
- Design Agent 复评 9.0/10
---
## 已实现的组件 API
### 布局组件
```typescript
import { Layout, Section, Article, Layer, Masthead, Rule } from '@newspaperui/components';
<Layout columns={24} maxWidth="1280px" padding="2rem" theme="light">
<Section columns={24} gap="2rem" breakable divider="bottom">
<Article span={8} breakable>
<Layer position="absolute" top="1rem" right="1rem" zIndex={10}>
<Masthead variant="classic" | "blackletter" | "modern" title kicker edition date price>
<Rule variant="hairline" | "double" | "thick" orientation="horizontal" | "vertical" span={N}>
```
### 文本组件
```typescript
import {
Headline, Subhead, Kicker, BodyText, Quote, Byline, Dateline, Caption,
} from '@newspaperui/components';
<Headline weight="High" | "Medium" | "Low" span={N} as="h1"|"h2"|"h3" align="left"|"center"|"right">
<Subhead weight="High" | "Medium" span={N}>
<Kicker>STANDARD SMALL CAPS RED</Kicker>
<BodyText weight="High"|"Medium"|"Low" columns={1|2|3|4} columnWidth="18em" columnFill="auto"|"balance" dropCap span={N}>
<p> 1em</p>
</BodyText>
<Quote variant="block" | "inline" weight="High" | "Medium">
<Byline>BY ALICE SMITH</Byline>
<Dateline>LONDON </Dateline>
<Caption credit="Photograph by ..."></Caption>
```
### 媒体组件
```typescript
<Image src alt span>
<Figure src alt caption credit span>
<Video src poster controls caption credit span>
<PullQuote weight="High" | "Medium" span spanAllColumns author align="left"|"center">
```
### Theme tokens
```css
/* CSS variables 已定义在 theme/src/variables.css */
--font-family-masthead, --font-family-blackletter, --font-family-display,
--font-family-headline, --font-family-body, --font-family-meta
--font-family-cjk-serif, --font-family-cjk-jp /* 新增:中日字体 */
--nui-bg-page #F7F4ED, --nui-bg-surface #FBF9F4
--nui-text-primary #1A1A1A, --nui-text-body #22201C, --nui-text-secondary, --nui-text-muted, --nui-text-quote
--nui-rule-hairline #C9C2B2, --nui-rule-decorative #1A1A1A
--nui-accent-primary #7A1F1F (NYT 朱红), --nui-accent-ink-blue #1B2A4A, --nui-highlight #F2E9C8
--nui-accent-cjk-red #CC2929 /* 新增:中文报纸朱红 */
/* 排版工具类(typography.css */
.nui-drop-cap, .nui-small-caps, .nui-paragraph-flow, .nui-osf, .nui-tnum,
.nui-hanging-punctuation, .nui-column-rule, .nui-avoid-break, .nui-span-all-columns,
.nui-masthead-rule-top, .nui-masthead-rule-bottom, .nui-rule-hairline
```
---
## 待实现:#15 Blocks 页面 6 个 demo
### 目标
参考 https://ui.shadcn.com/blocks,新建 `/blocks` 路由展示 6 个完整报纸 demo:
1. **中文头版**`/blocks/zh-frontpage`
2. **中文副刊专题**`/blocks/zh-feature`
3. **英文长篇专题**`/blocks/en-feature`)(NYT 头版已存在于 `/examples/nyt-frontpage`,本 Block 是不同类型)
4. **日语横排头版**`/blocks/jp-horizontal`
5. **日语竖排头版**`/blocks/jp-vertical`
6. (第 6 个根据需要自行决定,可以是中文政论或日语副刊)
### 用户已确认的设计决策
- **中文字体**Noto Serif SC(思源宋体),已加入 `theme/src/fonts.css``--font-family-cjk-serif` token
- **中文配色**:克制用红——仅报头 + Kicker 用 `--nui-accent-cjk-red #CC2929`,正文仍是暖灰系
- **中文排版**:紧凑、板块多、信息密度高
- **日语排版**:横排 + 竖排两种都做。竖排用 `writing-mode: vertical-rl`
- **日语字体**Noto Serif JP,已加入 token
### 用户反馈的核心痛点
> demo 应该要缜密,紧凑。当然如果有必要,也是可以有适当的留白。不过总体来说,传统时代,报纸区域是存土存金的。
**关键**:6 个 demo 都要充分利用空间,**不能有大片空白**,否则用户会再次不满意。
### Blocks 索引页
新建 `packages/docs/app/blocks/page.tsx`,参考 shadcn Blocks 页面结构:
```tsx
'use client';
import Link from 'next/link';
import { Layout, Section, Article, Headline, Subhead, Kicker } from '@newspaperui/components';
const blocks = [
{ href: '/blocks/zh-frontpage', lang: 'CHINESE · 中文', title: '人民周报 · 头版', preview: '/zh-frontpage-thumb.png' },
{ href: '/blocks/zh-feature', lang: 'CHINESE · 中文', title: '副刊 · 文化专题' },
{ href: '/blocks/en-feature', lang: 'ENGLISH', title: 'The Daily Chronicle · Long-form Feature' },
{ href: '/blocks/jp-horizontal', lang: 'JAPANESE · 日本語', title: '朝日新聞 · 横組み' },
{ href: '/blocks/jp-vertical', lang: 'JAPANESE · 日本語', title: '朝日新聞 · 縦組み(traditional' },
{ href: '/blocks/zh-editorial', lang: 'CHINESE · 中文', title: '社论 · 时事评论' }, // 第 6 个
];
export default function BlocksIndex() {
// 类似 Landing Page 的卡片网格,每个卡片链接到对应 block
}
```
**注意**:每个 Block 是 **完整一页**(不要嵌套在 Sidebar 内),所以 `/blocks``/blocks/[slug]` 都应该放在 `app/blocks/` 而不是 `app/(docs)/blocks/`,类似 `/examples/nyt-frontpage` 的处理方式。
### Block 1:中文头版 `/blocks/zh-frontpage`
完整代码模板(要求紧凑、信息密度高):
```tsx
import { Layout, Section, Article, Masthead, Rule, Headline, Subhead, Kicker, BodyText, Byline, Dateline, Figure, PullQuote } from '@newspaperui/components';
const cnStyle = { fontFamily: 'var(--font-family-cjk-serif)' };
const cnKickerStyle = { fontFamily: 'var(--font-family-cjk-serif)', color: 'var(--nui-accent-cjk-red)' };
export default function ZhFrontPage() {
return (
<Layout columns={24} maxWidth="1280px" padding="2rem 1.5rem" style={cnStyle}>
{/* 中文报头:朱红粗黑标题 + 双线 */}
<header style={{ textAlign: 'center', borderTop: '4px solid var(--nui-accent-cjk-red)', borderBottom: '1px solid var(--nui-rule-decorative)', paddingTop: '1rem', paddingBottom: '0.5rem' }}>
<div style={{ fontFamily: 'var(--font-family-meta)', fontSize: '11px', color: 'var(--nui-text-muted)', letterSpacing: '0.2em', marginBottom: '0.25rem' }}>RENMIN ZHOUBAO · </div>
<h1 style={{ ...cnStyle, fontSize: '88px', fontWeight: 900, color: 'var(--nui-accent-cjk-red)', margin: '0', letterSpacing: '0.1em', lineHeight: 1 }}></h1>
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '12px', color: 'var(--nui-text-secondary)', padding: '0.5rem 1rem', borderTop: '1px solid var(--nui-rule-hairline)', marginTop: '0.5rem', ...cnStyle }}>
<span> 2026 · 5891 </span>
<span>2026519 </span>
<span> 5 </span>
</div>
</header>
{/* 头条区:跨 24 列大标题 + 副标 + 双栏正文 */}
<Section columns={24} gap="1.5rem" style={{ marginTop: '1.5rem', paddingBottom: '1.5rem', borderBottom: '2px solid var(--nui-rule-decorative)' }}>
<Article span={24}>
<div style={{ ...cnKickerStyle, fontSize: '13px', fontWeight: 700, marginBottom: '0.5rem', textAlign: 'center' }}></div>
<h2 style={{ ...cnStyle, fontSize: '56px', fontWeight: 900, lineHeight: 1.1, color: 'var(--nui-text-primary)', textAlign: 'center', margin: '0' }}>
</h2>
<h3 style={{ ...cnStyle, fontSize: '24px', fontWeight: 500, lineHeight: 1.4, color: 'var(--nui-text-secondary)', textAlign: 'center', margin: '0.5rem 0 1rem 0' }}>
</h3>
<div style={{ textAlign: 'center', fontSize: '12px', color: 'var(--nui-text-muted)', ...cnStyle, marginBottom: '1rem' }}>
</div>
<BodyText weight="Medium" columns={3} dropCap style={cnStyle}>
<p> </p>
<p> 2040 2028 </p>
<p> 1.2% 0.7%</p>
<p></p>
<p>便</p>
<p></p>
</BodyText>
</Article>
</Section>
{/* 二条区:3 栏并列(要闻 / 经济 / 文化) */}
<Section columns={24} gap="1.5rem" style={{ marginTop: '1.5rem', paddingBottom: '1.5rem', borderBottom: '1px solid var(--nui-rule-decorative)' }}>
<Article span={8} style={{ borderRight: '1px solid var(--nui-rule-hairline)', paddingRight: '1rem' }}>
<div style={{ ...cnKickerStyle, fontSize: '12px', fontWeight: 700, marginBottom: '0.5rem' }}></div>
<h3 style={{ ...cnStyle, fontSize: '22px', fontWeight: 700, lineHeight: 1.3, color: 'var(--nui-text-primary)', margin: '0 0 0.5rem 0' }}></h3>
<BodyText weight="Low" style={cnStyle}>
<p></p>
<p></p>
</BodyText>
<Rule variant="hairline" style={{ margin: '1rem 0' }} />
<h4 style={{ ...cnStyle, fontSize: '17px', fontWeight: 600, lineHeight: 1.3, margin: '0 0 0.4rem 0' }}>线</h4>
<BodyText weight="Low" style={cnStyle}>
<p>亿线线</p>
</BodyText>
</Article>
<Article span={8} style={{ borderRight: '1px solid var(--nui-rule-hairline)', paddingRight: '1rem' }}>
<div style={{ ...cnKickerStyle, fontSize: '12px', fontWeight: 700, marginBottom: '0.5rem' }}></div>
<h3 style={{ ...cnStyle, fontSize: '22px', fontWeight: 700, lineHeight: 1.3, color: 'var(--nui-text-primary)', margin: '0 0 0.5rem 0' }}> PMI </h3>
<BodyText weight="Low" style={cnStyle}>
<p> 52.4</p>
<p></p>
</BodyText>
<Rule variant="hairline" style={{ margin: '1rem 0' }} />
<h4 style={{ ...cnStyle, fontSize: '17px', fontWeight: 600, lineHeight: 1.3, margin: '0 0 0.4rem 0' }}> 3.7%</h4>
<BodyText weight="Low" style={cnStyle}>
<p></p>
</BodyText>
</Article>
<Article span={8}>
<div style={{ ...cnKickerStyle, fontSize: '12px', fontWeight: 700, marginBottom: '0.5rem' }}> · </div>
<h3 style={{ ...cnStyle, fontSize: '22px', fontWeight: 700, lineHeight: 1.3, color: 'var(--nui-text-primary)', margin: '0 0 0.5rem 0' }}></h3>
<BodyText weight="Low" style={cnStyle}>
<p>殿</p>
<p></p>
</BodyText>
<Rule variant="hairline" style={{ margin: '1rem 0' }} />
<h4 style={{ ...cnStyle, fontSize: '17px', fontWeight: 600, lineHeight: 1.3, margin: '0 0 0.4rem 0' }}></h4>
<BodyText weight="Low" style={cnStyle}>
<p> 18%</p>
</BodyText>
</Article>
</Section>
{/* 三条区:4 栏短讯 + 1 列要点提示 */}
<Section columns={24} gap="1rem" style={{ marginTop: '1.5rem' }}>
<Article span={6} style={{ background: 'var(--nui-bg-surface)', padding: '1rem', borderLeft: '3px solid var(--nui-accent-cjk-red)' }}>
<div style={{ ...cnKickerStyle, fontSize: '11px', fontWeight: 700, marginBottom: '0.5rem' }}></div>
<ul style={{ ...cnStyle, fontSize: '14px', lineHeight: 1.6, paddingLeft: '1.2em', margin: 0, color: 'var(--nui-text-body)' }}>
<li> · A2</li>
<li> · A4</li>
<li> · B1</li>
<li> · C3</li>
<li> · C5</li>
<li> · D2</li>
</ul>
</Article>
<Article span={18}>
<div style={{ ...cnKickerStyle, fontSize: '12px', fontWeight: 700, marginBottom: '0.5rem' }}> · </div>
<BodyText weight="Low" columns={3} style={cnStyle}>
<p><strong></strong> 8000 西</p>
<p><strong></strong> </p>
<p><strong></strong> 退</p>
<p><strong></strong> </p>
<p><strong></strong> </p>
<p><strong></strong> </p>
</BodyText>
</Article>
</Section>
</Layout>
);
}
```
### Block 2-6 实施要点
#### Block 2:中文副刊专题 `/blocks/zh-feature`
- 风格:人物访谈 / 文化评论
- 结构:大幅人物图片(左侧 12 列)+ 长篇访谈正文(右侧 12 列双栏)
- 报头较小,强调内容深度
- 多用 Quote 组件呈现采访对话
- 字体仍是 Noto Serif SC,配色克制(仅小标签用朱红)
#### Block 3:英文长篇专题 `/blocks/en-feature`
- The Atlantic / The New Yorker 风格的 long-form
- 单栏阅读模式(窄栏宽 ≤ 700px)
- 大幅 hero image,下方居中标题 + drop cap
- 多个 PullQuote 穿插在正文中
- 用 Source Serif 4 + 经典严肃风配色
#### Block 4:日语横排头版 `/blocks/jp-horizontal`
- 朝日新闻 Web 版风格
- 横排,使用 Noto Serif JP
- 24 列栅格保持
- Masthead 用 Noto Serif JP 大字
- 关键:日语 Headline 没有英文 small capsKicker 改用普通粗体或方括号【速報】
- 段落首行不缩进(日语传统)
```tsx
const jpStyle = { fontFamily: 'var(--font-family-cjk-jp)' };
const jpKicker = { fontFamily: 'var(--font-family-cjk-jp)', color: 'var(--nui-accent-cjk-red)', fontSize: '13px', fontWeight: 700 };
// 日语 BodyText 不要用 dropCap(日文不适合)
// 不要用 nui-paragraph-flow 的 text-indent: 1em(日语传统首行不缩进)
// 改用普通 div 包 p
```
#### Block 5:日语竖排头版 `/blocks/jp-vertical`
- 关键:`writing-mode: vertical-rl;`
- Layout 容器需要 `height` 而不只是 `width`
- 不使用 BodyText 的 columns propCSS columns 与 vertical writing-mode 不兼容),改用多个独立 BodyText 块横向排列模拟栏
- 文字方向、border 方向都翻转
- 这是最难的一个,建议简化结构:报头 + 1 个头条 + 3-4 个并列竖排栏
```tsx
<div style={{
writingMode: 'vertical-rl',
height: '90vh',
fontFamily: 'var(--font-family-cjk-jp)',
display: 'flex',
flexDirection: 'row-reverse',
gap: '1.5rem',
padding: '2rem',
}}>
{/* 每个区块都是竖排 */}
</div>
```
#### Block 6:第 6 个 demo
建议做 **中文社论 / 时事评论**`/blocks/zh-editorial`):
- 双栏对开(左侧主社论 + 右侧专家评论)
- 引用密集,多用 Quote variant="block"
- 末尾署名
或换成 **韩文 / 阿拉伯文报纸** 都可以(用户没指定,自由发挥但要保证质量)。
### 实施建议
1. **拆 3 个 agent,每个做 2 个 demo**(每个 prompt 控制在 8000 token 以内)
- Agent ABlock 1 中文头版 + Block 2 中文副刊
- Agent BBlock 3 英文专题 + Block 6 中文社论
- Agent CBlock 4 日语横排 + Block 5 日语竖排
2. **每个 demo 完成后跑 `pnpm --filter @newspaperui/docs build`** 验证
3. **建立 `/blocks` 索引页**:参考 Landing Page 的卡片网格结构
4. **关键约束**:每个 demo 必须填满,不能有大片空白。栏数多、信息密度高、紧凑
### 路由结构最终目标
```
app/
page.tsx # Landing Page (报纸风格)
layout.tsx # 根 layout (含 Header)
globals.css
blocks/ # NEW
page.tsx # Blocks 索引
zh-frontpage/page.tsx # NEW
zh-feature/page.tsx # NEW
en-feature/page.tsx # NEW
jp-horizontal/page.tsx # NEW
jp-vertical/page.tsx # NEW
zh-editorial/page.tsx # NEW
examples/
nyt-frontpage/page.tsx # 已有:NYT 头版(迁移自原首页)
blackletter-frontpage/page.tsx # 已有:FAZ 头版
(docs)/
layout.tsx # 已有:Sidebar + Header 余高
grid-system/page.tsx
text/page.tsx
theme/page.tsx
components/{article,masthead,media,rule}/page.tsx
examples/{spanning,responsive}/page.tsx
```
---
## 待实现:#13 Stage 6 — JSDoc + README
### JSDoc 补全(18 个组件)
`packages/components/src/{layout,text,media}/*.tsx` 的每个组件补 JSDoc
```typescript
/**
* BodyText — 报纸正文组件
*
* 核心特性:
* - 多栏文字流:`columns={2|3|4}` 启用 CSS multi-column
* - 首字下沉:`dropCap` 触发 ::first-letter 4.2em float
* - 段落规则:默认开启段间无空行 + 首行缩进 1em + old-style figures + 悬挂引号
*
* @example
* <BodyText weight="High" columns={3} dropCap>
* <p>第一段...</p>
* <p>第二段(首行自动缩进 1em...</p>
* </BodyText>
*/
export const BodyText: React.FC<BodyTextProps> = ...
```
每个组件至少包含:
- 一句话描述
- 核心 prop 说明
- 一个使用示例
### README 更新
更新根目录 `README.md`
```markdown
# NewspaperUI
> Production-grade newspaper layout component library for the modern web.
参考 InDesign 与经典严肃风排版传统(NYT / The Times / FAZ),基于 24 列栅格、CSS Grid + Multi-column 双层机制。
## Quick Start
```bash
pnpm add @newspaperui/components @newspaperui/theme
```
```tsx
import '@newspaperui/theme';
import { Layout, Section, Article, Masthead, BodyText } from '@newspaperui/components';
<Layout columns={24}>
<Masthead variant="classic" title="The Daily Chronicle" date="..." />
<Section columns={24}>
<Article span={14}>
<BodyText columns={3} dropCap>...</BodyText>
</Article>
</Section>
</Layout>
```
## Packages
- `@newspaperui/theme` — CSS variables, visual weights, typography utilities
- `@newspaperui/utils` — Grid validation utilities
- `@newspaperui/components` — 18 React components
- `@newspaperui/docs` — Next.js documentation site
## Components (18)
### Layout
- Layout, Section, Article, Layer, Masthead, Rule
### Text
- Headline, Subhead, Kicker, BodyText, Quote, Byline, Dateline, Caption
### Media
- Image, Figure, Video, PullQuote
## Visual Design
- Typography: Cormorant Garamond (masthead), Source Serif 4 (display/body), Inter (meta), UnifrakturMaguntia (blackletter), Noto Serif SC/JP (CJK)
- Colors: warm off-white #F7F4ED background, #1A1A1A primary text, #7A1F1F NYT-style accent
- Layout: CSS Grid + Multi-column hybrid
## Development
```bash
pnpm install
pnpm build # build all packages
pnpm test # 29 tests
pnpm --filter @newspaperui/docs dev # http://localhost:3000
```
See `design.md` for full design specification.
See `SKILL.md` for the agent-driven workflow methodology used to build this project.
```
---
## 已知问题与陷阱
1. **'use client' 指令**:所有用了 `createContext` / `useState` 的组件必须有 `'use client'`,且页面 import 它们时如果整个页面调用了 React 客户端 API,页面也要加 `'use client'`。已知页面:所有有 `<Link>` 或 client-side state 的页面已加。
2. **Vite dts 偶尔不生成**:如果 components 包构建后 `dist/index.d.ts` 缺失,重跑 `pnpm --filter @newspaperui/components build` 就好。
3. **TypeScript strict mode**`noUnusedLocals` 严格,未使用的 import 会报错。新建 page 时记得清理。
4. **CSS columns 与 vertical-rl 不兼容**:日语竖排 demo 不能用 BodyText 的 columns prop。
5. **Sidebar 路径**`(docs)/layout.tsx` import Sidebar 用 `'../../components/Sidebar'`(路由组括号不算路径层级)。
6. **Theme 包导出**`packages/theme/package.json` 的 `exports` 字段需要 `./dist/style.css`(已加),否则 docs 包 import 会报 ERR_PACKAGE_PATH_NOT_EXPORTED。
7. **Next 15 的 metadata 会让 client component 失败**root layout 中 `export const metadata` 必须在 server component 文件中。client component 用 `'use client'` 后不能 export metadata。
---
## 验收清单(让接手 AI 验证完成度)
执行以下命令,全部通过即视为完成:
```bash
cd /Users/joi-com/Desktop/space/newspaperui
# 1. 全量构建
pnpm build
# 期望:4 packages 全部 successful
# 2. 测试
pnpm --filter @newspaperui/utils test # 11 tests pass
pnpm --filter @newspaperui/components test # 18 tests pass
# 3. 启动 dev server
pnpm --filter @newspaperui/docs dev
# 浏览器访问验证:
# http://localhost:3000 Landing Page
# http://localhost:3000/blocks Blocks 索引
# http://localhost:3000/blocks/zh-frontpage 中文头版
# http://localhost:3000/blocks/zh-feature 中文副刊
# http://localhost:3000/blocks/en-feature 英文专题
# http://localhost:3000/blocks/jp-horizontal 日语横排
# http://localhost:3000/blocks/jp-vertical 日语竖排(writing-mode: vertical-rl
# http://localhost:3000/blocks/zh-editorial 第 6 个 demo
# http://localhost:3000/examples/nyt-frontpage NYT 头版
# http://localhost:3000/examples/blackletter-frontpage FAZ 头版
# http://localhost:3000/grid-system, /text, /theme 文档章节
# 4. 视觉检查
# - 6 个 Blocks demo 不能有大片空白
# - 中文用 Noto Serif SC,仅报头 + Kicker 用朱红
# - 日语竖排 writing-mode: vertical-rl 真实生效
# - Header 在所有页面 sticky 顶部
# - Sidebar 仅在 (docs) 路由组下显示
```
---
## 文件位置速查
```
/Users/joi-com/Desktop/space/newspaperui/
├── HANDOFF.md 本文档
├── SKILL.md 工作流方法论
├── design.md 设计规范(修订版)
├── packages/
│ ├── theme/src/
│ │ ├── fonts.css 含 Noto Serif SC/JP 字体引入
│ │ ├── variables.css --font-family-cjk-serif/-jp、--nui-accent-cjk-red 已加
│ │ ├── visual-weights.ts 18 档视觉权重映射
│ │ ├── typography.css 排版工具类
│ │ └── tailwind.config.js
│ ├── utils/src/
│ │ ├── grid.ts validateSpan / clampSpan
│ │ ├── cx.ts 类名合并
│ │ └── index.ts
│ ├── components/src/
│ │ ├── layout/ Layout/Section/Article/Layer/Masthead/Rule
│ │ ├── text/ Headline/Subhead/Kicker/BodyText/Quote/Byline/Dateline/Caption
│ │ ├── media/ Image/Figure/Video/PullQuote
│ │ └── index.ts
│ └── docs/
│ ├── app/
│ │ ├── page.tsx Landing Page
│ │ ├── layout.tsx 含 <Header />
│ │ ├── globals.css
│ │ ├── (docs)/ Sidebar 包裹的章节
│ │ │ ├── layout.tsx
│ │ │ ├── grid-system/page.tsx
│ │ │ ├── text/page.tsx
│ │ │ ├── theme/page.tsx
│ │ │ ├── components/{article,masthead,media,rule}/page.tsx
│ │ │ └── examples/{spanning,responsive}/page.tsx
│ │ └── examples/ 全宽页面(不在 Sidebar 内)
│ │ ├── nyt-frontpage/page.tsx NYT 头版(已迁移)
│ │ └── blackletter-frontpage/page.tsx FAZ 头版
│ └── components/
│ ├── Header.tsx 全局 sticky 顶部导航
│ ├── Sidebar.tsx sticky top: 65px
│ ├── Demo.tsx, CodeBlock.tsx, PropsTable.tsx, ThemeToggle.tsx
```
---
## 接手 AI 的工作步骤建议
1. **读这个文档全文** + `design.md` + `SKILL.md`
2. **跑 `pnpm build` + `pnpm dev`** 确认现状
3. **访问 Landing Page http://localhost:3000** 看到当前布局
4. **从 #15 Block 1 中文头版开始**,按上面的代码模板落地
5. **每完成 1 个 demo 跑一次 build** 确认无 error
6. **用浏览器肉眼或 Playwright 截图验收**:是否紧凑、无空白
7. **6 个 Blocks 完成后做 #13**JSDoc + README
8. **最后跑一次 Design Agent 复评**(参考 SKILL.md 里的方法)
预计剩余工作量:
- #15 Blocks6 个 demo + 索引页):4-6 小时(拆 3 个 agent 并行可压缩到 1.5 小时)
- #13 JSDoc + README1 小时
- 总计:约 2-3 小时(用 agent 并行)