6.0 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
项目:缠论研习社——缠中说禅《教你炒股票》原文与杂文的沉浸式阅读站。
命令
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」。
<!-- ❌ 不要:纯工具类堆叠,用户无法指代 -->
<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/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)。
- CSS 已在
verbatimModuleSyntax: true:类型 import 必须写import type { ... }。