95 lines
6.0 KiB
Markdown
95 lines
6.0 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
项目:缠论研习社——缠中说禅《教你炒股票》原文与杂文的沉浸式阅读站。
|
||
|
||
## 命令
|
||
|
||
```bash
|
||
pnpm install # 安装依赖(需 Node 20+ 与 pnpm)
|
||
pnpm dev # 开发服务器 → http://localhost:5173(vite open 自动开浏览器)
|
||
pnpm build # vue-tsc -b 类型检查 + vite 生产构建
|
||
pnpm build:only # 跳过类型检查,仅 vite build
|
||
pnpm typecheck # 仅 vue-tsc -b 类型检查(改完 TS/Vue 先跑这个)
|
||
pnpm preview # 预览生产构建
|
||
```
|
||
|
||
本机 pnpm v11 用 `pnpm-workspace.yaml` 的 `allowBuilds`(不是 `onlyBuiltDependencies`)放行 esbuild / vue-demi 的构建脚本;新增带构建脚本的 devDep 时需在此手动放行,否则安装会被拦。
|
||
|
||
## 样式约定(重要)
|
||
|
||
### 每个用 Tailwind 写的元素必须带一个「标记类名」
|
||
|
||
用 Tailwind 工具类写样式时,**必须给每个有独立含义的元素加一个语义化的标记 class,并放在 class 列表最前面**。这样用户在对话里能精确指代「改哪个 div」。
|
||
|
||
```vue
|
||
<!-- ❌ 不要:纯工具类堆叠,用户无法指代 -->
|
||
<div class="flex items-center gap-2 rounded-md bg-surface px-3 py-2">
|
||
|
||
<!-- ✅ 要:标记类名打头(组件名__部位,kebab-case) -->
|
||
<div class="article-card__lesson flex items-center gap-2 rounded-md bg-surface px-3 py-2">
|
||
```
|
||
|
||
命名规则:`<组件或区块名>__<部位>`,如 `home-hero__title`、`reader-meta`、`article-card__tags`。一个 `.vue` 文件内的标记类名以该组件的功能名为前缀,保证跨组件不撞。
|
||
|
||
> 现存组件(如 `ArticleCard.vue`)尚未遵循此约定;**新建或重写元素时一律补上**,改动既有元素时顺手补。
|
||
|
||
### 颜色必须走设计 Token,禁止裸色值
|
||
|
||
所有颜色用 `src/style.css` 里 `@theme inline` 定义的语义类,**不要写 `bg-white` / `text-gray-500` / `#fff` 这类**:
|
||
|
||
- 背景:`bg-app`(应用底)/ `bg-background`(卡片)/ `bg-surface` / `bg-surface-2` / `bg-hover`
|
||
- 文本:`text-foreground` / `text-muted` / `text-subtle` / `text-faint`
|
||
- 品牌/语义:`text-primary` / `bg-primary-soft` / `text-success` / `text-warning` / `text-danger`
|
||
- 边框:`border-line` / `border-line-strong` / `border-line-card`
|
||
- 圆角用 `rounded-xs/sm/md/lg/xl/2xl`(4/8/12/16/20/24),阴影用 `shadow-xs/sm/soft/md/lg/xl`
|
||
|
||
亮/暗主题切换靠 `<html class="dark">`,所有语义色自动适配——**只要用 Token,就不用单独写 dark: 变体**。
|
||
|
||
### class 合并用 `cn()`
|
||
|
||
`src/utils/cn.ts` 的 `cn()` = clsx(条件)+ tailwind-merge(冲突后写覆盖前写,如 `px-2 px-4 → px-4`)。有条件 class 或动态拼接时用它,别手写字符串拼接。
|
||
|
||
## 架构(需要跨文件理解的)
|
||
|
||
**技术栈**:Vue 3 `<script setup>` + Vite 6 + Tailwind v4(CSS-first `@theme`)+ TS strict + Pinia + Vue Router 4 + markdown-it + lucide-vue-next。`@` 别名 → `src/`。
|
||
|
||
### 数据层是完全解耦的(核心设计)
|
||
|
||
页面不直接读数据文件,而是通过 `src/composables/useArticles.ts`:它把 `chanlunLessons`(`data/chanlun.ts`)和 `essays`(`data/essays.ts`)合并,提供 `chanlun / essaysList / latest / featured / find() / neighbors() / search()`。
|
||
|
||
- 接入真实抓取数据时:只改数据源(替换 `data/*.ts`)或把 `useArticles.ts` 内的静态数组改成异步请求,**页面和组件无需改动**。
|
||
- 文章正文是 **markdown 字符串**(`Article.content`,见 `types/article.ts`)。抓取的 HTML 入库时转 markdown,或扩展 `useMarkdown.ts` 直接渲染 HTML。
|
||
|
||
### 文章正文排版 = `.prose-chan`(不要手写)
|
||
|
||
正文区一律挂 `prose-chan` 类(定义在 `style.css` 的 `@layer components`),它已处理 h2/h3/p/blockquote/code/table/列表等全部排版。字号/字体不写死,而是通过 `data-size`(`sm|base|lg|xl`)和 `data-font`(`serif|sans`)属性驱动,值来自 reading store。
|
||
|
||
### 两个 Pinia store 驱动全局体验
|
||
|
||
- `stores/theme.ts`:`light | dark | system`,持久化到 `localStorage['chan-theme']`,靠给 `<html>` 加 `.dark` 生效。
|
||
- `stores/reading.ts`:字号 / 字体 / 专注模式,分别持久化。
|
||
- **防闪烁(FOUC)**:`index.html` 里有段内联脚本在 Vue 挂载前同步读 `chan-theme` 加 `.dark`。改主题存储 key 时,`index.html` 脚本和 `stores/theme.ts` 必须**同步改**,否则首屏会闪。
|
||
|
||
### 路由与布局
|
||
|
||
5 个 view,两种 layout:
|
||
- `DefaultLayout`(`/`):顶栏 + 侧栏 + 内容 + 页脚,包 home / chanlun / articles / about。
|
||
- `ReaderLayout`(`/read/:category/:slug`):沉浸阅读,含阅读进度、阅读设置、上下篇导航。
|
||
- markdown 的 h2/h3 会被 `useMarkdown.ts` 注入 `id`(slug 来自 `utils/slug.ts`),便于锚点跳转。
|
||
|
||
### 现存组件缺标记类名
|
||
|
||
`components/ui/`(BaseButton/Badge/Card/SearchInput)、`components/layout/`(AppHeader/AppSidebar/AppFooter)及 `ArticleCard` 等目前是纯工具类。改动它们时按上面的「标记类名」约定补齐。
|
||
|
||
## 其他约定
|
||
|
||
- TS strict 且开了 `noUnusedLocals` / `noUnusedParameters`:**未用的 import / 变量会直接让 `pnpm build` 失败**,删代码时记得清干净。
|
||
- `<script setup lang="ts">` + Composition API。
|
||
- 图标:默认用 `lucide-vue-next`(Vue 组件,按需 tree-shake)。另装了 **Remix Icon**(webfont)补 lucide 缺的图标,品牌 Logo 即用 `ri-line-chart-line`:
|
||
- CSS 已在 `main.ts` 全局引入 `remixicon/fonts/remixicon.css`,直接用 `<i class="ri-xxx-line" aria-hidden="true"></i>`。
|
||
- webfont 字号靠 `text-*`(font-size 驱动,不用 `size-*`);颜色继承 `currentColor`,所以放在 `text-white` 的容器里就是白色。
|
||
- 图标名查 https://remixicon.com(v4.9,无 candlestick;走势/图表类可用 `ri-line-chart-line` / `ri-bar-chart-line` / `ri-stock-line` / `ri-funds-line`)。
|
||
- `verbatimModuleSyntax: true`:类型 import 必须写 `import type { ... }`。
|