# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build & Development ```bash # WeChat mini-program npm run dev:weapp # Watch/dev build → weapp/ npm run build:weapp # Production build → weapp/ # H5 (web) npm run dev:h5 # Watch/dev build → build/ npm run build:h5 # Production build → build/ ``` Output directories are determined by `TARO_ENV`: for H5 it's `build/`, for all other platforms it matches the platform name (e.g., `weapp/`). No test or lint scripts are configured. ESLint (`eslint-config-taro`) and Stylelint are installed but must be run manually. ## Architecture This is a **Taro 3.6** cross-platform app using **React 18** (concurrent mode), **TypeScript**, and **Webpack 5**. It targets WeChat, Alipay, DingTalk, JD, Kwai, QQ, Baidu, Toutiao mini-programs, and H5 web. ### UI Library: `@antmjs/vantui` The UI library is `@antmjs/vantui` (v3), a Taro-compatible port of Vant. Components are imported from `@antmjs/vantui` directly (e.g., `import { Button } from '@antmjs/vantui'`). The `babel-plugin-import` in `babel.config.js` handles on-demand style imports. ### Page Structure Each page lives in `src/pages//` and consists of three files: - `index.tsx` — page component (functional or class) - `index.config.ts` — page-level config (title, navigation style, etc.) - `index.less` — page styles Pages must be registered in `src/app.config.ts` under the `pages` array. ### Path Alias `@` maps to `src/` (configured in `config/index.js`). ### Theme & Global Styles - `src/app.less` — global app styles (imported in `app.ts`) - `src/styles/index.less` — theme variable overrides for Vant UI. It imports `@antmjs/vantui/es/style/var.less` and uncomments/redefines Less variables to customize the theme. This file is injected into every `.less` file via Less `modifyVars` (configured in `config/index.js` under both `mini.lessLoaderOption` and `h5.lessLoaderOption`). ### Webpack Customizations (`config/webpack/`) - **`commonChain.js`** — Overrides Taro's default `script` rule `exclude` so that Babel also processes these `node_modules` packages: `taro`, `inversify`, `@antmjs`, `react-spring`, `recoil`, `buffer`, `qrcode`. Do NOT include "taro" in the project name or all node_modules will be recompiled. - **`miniChain.js`** — Applied to mini-program builds. Adds: - `MiniFixPlugin` — fixes path param encoding differences between WeChat/Douyin and Alipay/DingTalk - `GlobalFixPlugin` — polyfills the `global` variable for Alipay, DingTalk, and Baidu mini-programs - **`h5Chain.js`** — Applied to H5 builds. Adds `H5FixPlugin` for H5 compatibility fixes. ### Build Config Layers `config/index.js` exports a function that merges the base config with `config/development.js` or `config/production.js` based on `NODE_ENV`. Environment variables: | Variable | Purpose | Default | |---|---|---| | `TARO_ENV` | Target platform (`weapp`, `h5`, `alipay`, etc.) | `weapp` | | `NODE_ENV` | Build mode | `production` | | `API_ENV` | API environment selector | `real` | - `designWidth: 750` — all px values are converted to rpx at this ratio - `@tarojs/plugin-framework-react` is configured with `reactMode: "concurrent"` (React 18 concurrent features) - `browserslist` targets iOS 9+ for production ### App Entry - `src/app.ts` — class-based App component, renders `this.props.children` (the current page) - `src/app.config.ts` — defines routes (`pages` array), window config, and app-level settings - `src/index.html` — H5 entry HTML template ## VantUI Component API Reference (v3.7) This project uses `@antmjs/vantui` v3.7. The official docs: https://antmjs.github.io/vantui/main/ **Always check the actual type definitions** in `node_modules/@antmjs/vantui/types/` when unsure about props. Key API notes for commonly used components: ### Search - `shape`: `'square'` (default) | `'round'` - `background`: background color string (default `#FFFFFF`) - `onFocus`, `onBlur`, `onChange`, `onSearch`, `onClear`, `onCancel` — event callbacks - `leftIcon`, `rightIcon` — icon name or image URL - `showAction` + `actionText` — right-side action button ### Swiper (NOT the same as Taro's native Swiper) - `autoPlay` — auto-play interval in ms (0 = disabled). **Not** `autoplay` - `loop` — infinite loop mode. **Not** `circular` - `paginationColor` — indicator dot color. **Not** `indicatorColor` - `paginationVisible` — show/hide pagination dots - `duration` — animation duration (default 500) - `width` / `height` — card dimensions - **No** `indicatorActiveColor` prop — only one `paginationColor` - `onChange` callback: `(currPage: number) => void` (not an event object) ### SwiperItem - Minimal component, only `className` and `children`. No special props. ### Grid / GridItem - `Grid`: `columnNum`, `border`, `gutter`, `square`, `clickable`, `center`, `iconSize` - `GridItem`: `icon` (string), `text` (ReactNode), `iconColor`, `dot`, `info`/`badge`, `url` + `linkType` ### Tabs / Tab (v3.7) - `Tabs`: - `active` — current tab index (number | string) - `sticky` — enable sticky mode - `offsetTop` — sticky offset in px. **Not** `stickyOffsetTop` - `color`, `titleActiveColor`, `titleInactiveColor` — color props - `type`: `'line'` | `'card'` - `swipeable` — enable swipe gesture switching - `animated` — enable tab switch animation - `ellipsis` — text overflow ellipsis (default true) - **No** `lineWidth` or `lineHeight` props - `onChange`: `(e: { detail: { index: number; name?: string; title?: string } }) => void` - `Tab`: `title` (ReactNode), `name` (identifier), `dot`, `info`, `disabled`, `titleStyle` ### Image (VantUI Image, not Taro's native Image) - `src`, `fit` (`'contain' | 'cover' | 'fill' | 'widthFix' | 'heightFix' | 'none'`), `width`, `height`, `radius` - `round` — circular image (boolean) - `lazyLoad`, `showError`, `showLoading` - `renderLoading`, `renderError` — custom render slots ### Common VantUI pattern: Taro's native components vs VantUI components - Use `@tarojs/components` for: `View`, `Text`, `ScrollView`, `Image` (native, simpler) - Use `@antmjs/vantui` for: styled UI components (Search, Swiper, Tabs, Grid, Button, etc.) - VantUI component props extend Taro's `ViewProps`, so `onClick`/`onTap` and style props are always available ## Custom TabBar (`src/custom-tab-bar/`) This project uses Taro's **custom tabBar** mechanism (`tabBar.custom: true` in `app.config.ts`). Key rules: ### Component location - The custom tabBar component MUST be at `src/custom-tab-bar/index.tsx` — this is a Taro convention, not configurable - Taro automatically renders this component on every tab page; do NOT import `` in individual pages ### Do NOT use CoverView - `CoverView` / `CoverImage` have known bugs on real devices: invisible, click events don't bubble - Use regular `` with `position: fixed; bottom: 0; z-index: 999` instead ### Active tab state - Taro creates a **new instance** of the tabBar component on each page, so `useState` resets on every tab switch - Derive the active tab from `Taro.getCurrentPages()` at render time — NOT from component state - Pattern: `const route = Taro.getCurrentPages()[last]?.route; const activeKey = TAB_LIST.find(t => route.includes(t.key))` ### Tab switching - Use `Taro.switchTab({ url: pagePath })` — this matches native tabBar behavior - The `pagePath` format must match the `tabBar.list[].pagePath` in `app.config.ts` ### Center "publish" button - The publish button is a UI-only element not in `tabBar.list` - It triggers a VantUI `` rendered as a sibling of the tabBar, NOT nested inside it - The popup state can use `useState` since it's ephemeral and not shared across tabs