feat: 完善课程模板通用能力

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhongyidianandClaude Opus 5 committed 2026-09-08 14:07:42 +08:00
1 parent 1e02c7835e
commit a641d0e2ea
70 files changed
+2868 -205

No files matched your search

+49 -7
View File
@@ -39,9 +39,14 @@ bun run lint:fix # 自动修复代码问题
新增文件前先判断职责归属,优先沿用现有目录结构:
- `src/components/common/`:通用可复用组件。新增通用组件后,按需在 `src/components/common/index.ts` 维护导出。
- `src/components/ui/`:无课程业务和全局状态依赖的基础 UI copied source。
- `src/components/common/`:模板通用组件和适配器;其中 `GuideDialog`、`GuideSpotlight` 负责连接 Zustand、CourseCanvas 与交互内核。新增通用组件后,按需在 `src/components/common/index.ts` 维护导出。
- `src/components/business/`:业务组合组件,不放通用基础能力。
- `src/course/canvas/`:设计稿画布、缩放、viewport 和课程 Portal 根节点。
- `src/course/orientation/`:横竖屏访问控制。
- `src/course/interactions/`:由 CLI 复制的受控课程交互内核,不依赖具体页面、Store 或 common 适配器。
- `src/pages/<PageName>/`:页面组件。页面目录入口使用 `index.tsx`,页面组件使用默认导出。
- 模块内私有组件:仅本模块使用、其他模块用不到的,放到本模块目录的 `components/` 子目录(没有就创建);被多个模块或组件复用才下沉到 `src/components/common/`(通用基础能力)或 `business/`(业务组合),按组件核心类型区分。该规则约束新代码,存量平铺在页面目录下的模块内组件不强制迁移。
- `src/router/index.tsx`:集中维护路由配置。新增页面优先复用 `lazyRoute` 和 `RouteFallback`。
- `src/stores/`:Zustand 状态管理。
- `src/utils/`:通用工具、hooks 或平台封装。
@@ -50,7 +55,7 @@ bun run lint:fix # 自动修复代码问题
### 类型放置规则
组件、页面、store、API 的 `props`、`interface`、`type` 不要直接写在实现文件里:
组件、页面、store、API 的对外 `props` 与跨文件共享的 `interface`、`type` 放在 `.types.ts`;文件内私有的 helper 类型留在实现文件即可:
- 组件类型放在同组件目录的 `组件名.types.ts`,例如 `Button/Button.types.ts`。
- 页面类型如确实需要,放在页面目录的 `PageName.types.ts`。
@@ -61,7 +66,7 @@ bun run lint:fix # 自动修复代码问题
## Tailwind、cn 与样式提取规则
项目已有 [src/utils/tailwind.ts](src/utils/tailwind.ts) 中的 `cn`,用于合并 Tailwind class 并处理冲突。使用时遵守以下边界。
项目已有 [src/lib/cn.ts](src/lib/cn.ts) 中的 `cn`,用于合并 Tailwind class 并处理冲突([src/utils/tailwind.ts](src/utils/tailwind.ts) 只是 re-export)。使用时遵守以下边界。
### 默认策略
@@ -74,7 +79,7 @@ bun run lint:fix # 自动修复代码问题
在以下场景使用 `cn`:
- 需要合并外部传入的 `className`。
- 存在条件 class。
- 条件 class 需要和其他 class 合并。
- 需要通过 `tailwind-merge` 解决 Tailwind 冲突合并。
- 需要组合 CSS Module、固定 class、条件 class 或外部 `className`。
@@ -90,9 +95,10 @@ bun run lint:fix # 自动修复代码问题
```tsx
<div className="flex items-center justify-center" />
<div className={active ? "h-2 w-8 bg-current" : "h-2 w-2 bg-current/20"} />
```
单个固定字符串且没有条件、合并、冲突处理需求时,直接写 `className="..."`。
单个固定字符串,或在两个完整字符串之间二选一的三元且不需要再合并其他 class 时,直接写 `className`。
### 什么时候提取样式
@@ -110,6 +116,38 @@ bun run lint:fix # 自动修复代码问题
- 同目录多个文件共享时,可放同目录局部文件。
- 跨组件复用的样式能力,再考虑沉淀为通用组件、工具或 CSS Module。
### 组件与 CSS 类的边界
「何时提取 class」见上一节;本节只解决复用一段 UI 时该抽组件还是抽 CSS 类。
组件/页面文件超过 500 行时,先审视是否该拆分(这是触发思考的信号,不是强制拆分线);拆出的子组件按「文件创建与目录归属」放置。
重复出现时优先抽组件,CSS 类是兜底,但避免「为整洁而抽」。抽组件必须同时满足:
- 同一组「标记 + 样式 + 行为」在 2 处以上真实重复(第一次出现不抽)。
- 组件有清晰可命名的语义,能一句话说清它是什么。
- 复用的是整体而非几个 class;props 少且稳定(一般 ≤3~4 个)。
以下情况改用 CSS 类或局部常量,而不是抽组件:
- 只复用样式、不复用标记/行为,内容由数据或富文本决定。
- 仅同一文件内的小重复。
- 给第三方/框架等无法插入组件的位置加样式。
- Tailwind 表达不了或 class 串过长,但元素本身不够独立语义。
反模式(不要抽):只被用一次仅为缩短 JSX;组件 props 塞满 className/style 覆盖;名字说不清职责(`CardTopSection`、`Wrapper` 之类)。
## 动画使用规则
项目使用 CSS/Tailwind 和 GSAP 时遵守以下边界:
- 普通状态过渡、hover、active、简单淡入淡出及单元素入场默认使用 CSS/Tailwind。
- 只有动画需要时间轴编排、暂停/继续/倒放、运行时动态计算、音视频同步或复杂路径时,才使用 GSAP。
- 不因项目已经安装 GSAP 而重写现有 CSS 动画,也不为简单动画建立 GSAP preset 或通用封装。
- CSS 与 GSAP 不要在同一交互周期内控制同一元素的同一属性,尤其是 `transform` 和 `opacity`。
- GSAP 动画通过 `src/utils/motion.ts` 使用 `useGSAP` 管理生命周期,并处理 `prefers-reduced-motion` 降级。
- 不使用 GSAP 修改 `CourseCanvas`、画布 portal 根节点或 dnd-kit 正在控制的 `transform`。
## 导入与导出
- `@` 指向 `src`,新增代码优先使用 `@` 避免过长相对路径。
@@ -129,10 +167,14 @@ bun run lint:fix # 自动修复代码问题
开发时要尊重模板已有能力:
- 页面按 `1920 x 1080` 设计稿开发,整体缩放由 `src/course-runtime/canvas` 的 `CourseCanvas` 组件承担。
- 横屏访问提示由 `src/course-runtime/orientation` 的 `OrientationGuard` 组件承担。
- 页面按 `1920 x 1080` 设计稿开发,整体缩放由 `src/course/canvas` 的 `CourseCanvas` 组件承担。
- 横屏访问提示由 `src/course/orientation` 的 `OrientationGuard` 组件承担。
- 易班能力通过 `src/utils/yiban.ts` 和 `public/videoajax/` 相关脚本封装。
- 移动端调试使用 `src/utils/vconsole.ts`。
- 图片按钮由 `src/components/common/ImageButton` 提供;视频播放与视频弹层由 `src/components/common/Video` 提供。
- 拖拽交互由 `src/course/interactions/drag-drop` 提供(基于 dnd-kit)。
- 音频能力由 `src/utils/audio` 提供(`GameAudioProvider` / `useGameAudio` / `AudioManager`)。
- GSAP 复杂动画通过 `src/utils/motion.ts` 统一引入,边界见「动画使用规则」。
- 新增通用组件时,同步考虑是否需要在 [src/pages/Components/index.tsx](src/pages/Components/index.tsx) 增加示例。
## Claude Code 工作准则