Generate a production-quality React + Vite storefront from a single product brief.
Default output includes: product catalog, cart, product detail, checkout, wishlist, admin dashboard, AI sales concierge, mock-to-live payment switching, and EdgeOne Pages deployment files.
This Skill is the authoritative source for all code conventions used across all generated stores.
Every agent invoking this Skill must follow the conventions below — no exceptions, no shortcuts.
templates/base/ into a new directory named -store/ .__PLACEHOLDERS__, translate ALL UI strings to the detected language (see Convention 0 translation map), fill in product data (Chinese name + English nameEn in zh mode), set brand colors in tailwind.config.js.npm run build and ensure zero TypeScript errors.npm run dev) and verify all routes are accessible.<brand-slug>-store/
├── index.html ← must contain Google Fonts + correct lang attr
├── package.json ← must include all required deps (see below)
├── tailwind.config.js ← must define font-body, font-heading, brand colors
├── vite.config.ts
├── tsconfig.json
├── .env.example
├── .gitignore
├── edgeone.json
├── src/
│ ├── main.tsx
│ ├── App.tsx ← route definitions
│ ├── styles.css
│ ├── vite-env.d.ts
│ ├── components/
│ │ ├── Navbar.tsx
│ │ ├── Footer.tsx
│ │ ├── ProductCard.tsx
│ │ ├── CartDrawer.tsx ← slide-out cart (REQUIRED, not optional)
│ │ └── AIChatWidget.tsx
│ ├── pages/
│ │ ├── HomePage.tsx
│ │ ├── ShopPage.tsx ← dedicated browse/filter/sort page (REQUIRED)
│ │ ├── ProductPage.tsx ← /product/:id — MUST exist and be routed
│ │ ├── CartPage.tsx ← fallback full-page cart
│ │ ├── CheckoutPage.tsx
│ │ ├── WishlistPage.tsx
│ │ └── AdminPage.tsx
│ ├── data/
│ │ └── products.ts ← typed product records
│ ├── store/
│ │ └── cartStore.ts ← Zustand with persist middleware
│ └── types/
│ └── index.ts
└── functions/
├── api/
│ ├── products.ts
│ ├── checkout.ts
│ └── assistant.ts
└── node/
└── stripe-webhook.ts
| Path | Page | Notes |
|---|---|---|
| ------------------ | ------------------ | ------------------------------ |
/ | HomePage | |
/shop | ShopPage | browse + filter + sort |
/product/:id | ProductPage | dynamic slug — MUST be wired |
/cart | CartPage | |
/checkout | CheckoutPage | |
/wishlist | WishlistPage | |
/admin | AdminPage |
// package.json dependencies (exact versions may float, list them all)
{
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.1",
"zustand": "^4.5.5",
"framer-motion": "^11.3.19",
"lucide-react": "^0.400.0",
"clsx": "^2.1.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"typescript": "^5.5.4",
"vite": "^5.4.2",
"tailwindcss": "^3.4.0",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.38"
}
}
These rules apply to every file generated by this Skill.
Any agent invoking this Skill must treat these as hard constraints, not suggestions.
Before scaffolding any project, detect the user's system locale and generate the UI in the matching language.
Detection protocol:
powershell -Command "Get-Culture | Select-Object -ExpandProperty Name" on Windows, or locale | grep LANG on macOS/Linuxzh (zh-CN, zh-TW, zh-HK, etc.) → generate ALL user-facing UI strings in Chinese (Simplified)en, ja, ko, etc.) → generate ALL user-facing UI strings in EnglishTranslation scope — every user-facing string MUST be translated:
Common UI translation map (for reference):
| English (template base) | 中文 (zh-CN output) |
|---|---|
| ------------------------ | --------------------- |
| Home | 首页 |
| Shop | 商城 / 全部商品 |
| New In | 新品上架 |
| Sale | 特惠 / 折扣 |
| Cart | 购物车 |
| Wishlist | 收藏夹 |
| Search products... | 搜索商品... |
| Add to Cart | 加入购物车 |
| Checkout | 结算 |
| Continue Shopping | 继续购物 |
| Proceed to Checkout | 去结算 |
| Subtotal | 小计 |
| Free Shipping over $X | 满 ¥X 免运费 |
| Shipping Info | 收货信息 |
| Payment & Promo | 支付与优惠 |
| Order Review | 确认订单 |
| Place Order | 提交订单 |
| Related Products | 相关推荐 |
| Category | 分类 |
| Sort by | 排序 |
| Price: Low to High | 价格从低到高 |
| Price: High to Low | 价格从高到低 |
| Rating | 评分 |
| Newest | 最新上架 |
| Filter | 筛选 |
| All | 全部 |
| Quantity | 数量 |
| Size | 规格 |
| Color | 颜色 |
| Remove | 删除 |
| Your cart is empty | 购物车是空的 |
| No products found | 没有找到商品 |
| AI Assistant | AI 购物助手 |
| Ask me anything... | 问我任何问题... |
| Bestsellers | 热销推荐 |
| New Arrivals | 新品上市 |
| Features | 特色服务 |
| Free Shipping | 免费配送 |
| Secure Payment | 安全支付 |
| Easy Returns | 无忧退换 |
| Contact Us | 联系我们 |
| About Us | 关于我们 |
| Privacy Policy | 隐私政策 |
| Terms of Service | 服务条款 |
| Newsletter | 订阅资讯 |
| Subscribe | 订阅 |
| Your email | 您的邮箱 |
Note: The above map is a reference baseline. The agent should use its own full translation ability for product descriptions, product names, and longer content — not just the map above.
Default font stack (apply to all generated projects):
"Helvetica Neue", Arial, sans-serifindex.html — required tag:
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&family=Playfair+Display:wght@400;700&display=swap" rel="stylesheet">
tailwind.config.js — required font definitions:
theme: {
extend: {
fontFamily: {
'body': ['Noto Sans SC', 'Inter', 'sans-serif'],
'display': ['Playfair Display', 'serif'],
},
},
},
styles.css — apply body font globally:
body {
font-family: 'Noto Sans SC', 'Inter', sans-serif;
}
All icons MUST use lucide-react components. Emoji is prohibited in all UI code.
Rules:
lucide-react: import { ShoppingCart, Heart, Star } from 'lucide-react'size={16} or size={20} — match surrounding text size with emoji content as icon substitutesCommon icon mappings:
| Old emoji | Lucide component |
|---|---|
| ----------- | ------------------- |
| 🛒 | |
| ❤️ / 💝 | |
| ⭐ / ✨ | |
| 🎉 | |
| 🚚 | |
| 📦 | |
| 🌿 | |
| ❄️ | |
| ✈️ | |
| 🔄 | |
| ✓ / ✅ | |
Prohibited font sizes:
All odd px values in text-[Xpx] Tailwind classes are forbidden.
Correction table:
| Forbidden | Use instead |
|---|---|
| ----------- | ------------- |
text-[11px] | text-[12px] |
text-[13px] | text-[14px] |
text-[15px] | text-[16px] |
text-[9px] | text-[10px] |
Rule: All pixel font sizes must be even numbers. Use Tailwind's standard scale (text-xs, text-sm, text-base, etc.) wherever possible; only use text-[Xpx] when a specific size is needed and it must be even.
All mock product images must return HTTP 200.
Protocol:
image URL in src/data/products.ts, verify the URL is reachable.```
https://images.unsplash.com/photo-
```
The cart store must use Zustand with the persist middleware so the cart survives page refresh:
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
export const useCartStore = create(
persist(
(set, get) => ({
items: [],
addItem: (product) => { /* ... */ },
removeItem: (id) => { /* ... */ },
updateQty: (id, qty) => { /* ... */ },
clearCart: () => set({ items: [] }),
total: () => get().items.reduce((sum, i) => sum + i.price * i.qty, 0),
}),
{ name: '<brand>-cart' }
)
)
The /product/:id route is critical. It must:
App.tsx as } />id param with const { id } = useParams()products.ts data by matching slug or idProductCard must navigate on click:
import { useNavigate } from 'react-router-dom'
const navigate = useNavigate()
// on card click:
navigate(`/product/${product.id}`)
// tailwind.config.js
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
fontFamily: {
'body': ['Noto Sans SC', '"Helvetica Neue"', 'Arial', 'sans-serif'],
'display': ['"Playfair Display"', 'serif'],
},
colors: {
// Override with brand-specific palette per project
brand: {
50: '#fafafa',
500: '#18181b',
900: '#09090b',
},
},
},
},
plugins: [],
}
Use framer-motion for all transitions. Standard presets:
// Card hover lift
whileHover={{ y: -4, scale: 1.02 }}
transition={{ duration: 0.2 }}
// Page enter
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
// Stagger children
variants={{ hidden: { opacity: 0 }, visible: { opacity: 1 } }}
transition={{ staggerChildren: 0.08 }}
tsconfig.json must have "strict": trueProduct interface in src/types/index.tsany unless in placeholder API handlerstsc --noEmit before delivery; fix all errorsBefore delivering the project, run:
npm install
npm run build
The build MUST complete without errors. If there are TypeScript errors, fix them before delivery.
A project that does not build is not a deliverable.
CRITICAL: These are NOT suggestions. Every generated project MUST meet all of the following minimum complexity levels. If time/effort is short, do FEWER pages but make them HIGHER quality rather than spreading thin. The test output standard is the FRAISE store method — match or exceed that quality level.
The project MUST have TWO separate Zustand stores, both with persist middleware:
1. cartStore — key '
items, addItem (merge same-product), removeItem, updateQty, clearCart, total(), count()2. wishlistStore — key '
ids: string[], toggle(id), has(id)Every project MUST define two complete color palettes (50–950), both semantic:
| Palette | Purpose | Examples |
|---|---|---|
| --------- | --------- | ---------- |
brand | Primary actions, highlights, CTAs | Warm orange #d4751a, amber, or deep red |
fresh / leaf | Organic/success badges, nature cues | Green #74ae58, teal #4EcDc4 |
The theme colors must feel appropriate for the product category. A fruit store uses warm orange + green; a tech store might use indigo + teal. Never use a single-palette or generic gray-only theme.
Minimum required classes (all MUST be defined and used):
| Class | Purpose |
|---|---|
| ------- | --------- |
btn-primary | Main CTA button (brand fill, white text, rounded-full, hover lift) |
btn-outline | Secondary button (brand border, brand text, transparent bg) |
btn-ghost | Tertiary link-style button (gray text, hover dark) |
tag | Capsule badge (uppercase, tracking-wider, rounded-full) |
section-title | Page section heading (text-2xl, font-display, font-semibold) |
section-subtitle | Section subtitle (text-sm, text-neutral-500) |
The HomePage MUST contain ALL of the following sections in order:
isNew products (4–8 items), with framer-motion fadeUp staggerA dedicated browse page (/shop) with:
?category=xxx)A slide-out drawer component (NOT an inline section in Navbar):
A three-step checkout flow with progress indicator, accessible via /checkout from CartDrawer or CartPage "Checkout" buttons:
^1[3-9]\d{9}$)clearCart()Critical bug fix required: Do NOT call clearCart() on initial submit — only clear after user confirms in step 3.
Progress indicator: 3-step horizontal stepper (numbered circles, step labels, connector lines), current step highlighted in brand color, completed steps show checkmark.
Sidebar: Sticky order summary panel (right side on desktop, hidden on mobile) showing:
Order confirmation after submission:
SL + timestamp base36)The component must accept a layout prop: 'grid' | 'list'
new Date().getFullYear())Every Product record MUST include ALL of these fields. No field is optional.
export interface Product {
id: string; // URL-safe slug
name: string; // Chinese product name
nameEn: string; // English product name
brand: string;
category: string;
price: number; // current price in CNY
originalPrice?: number; // crossed-out price
images: string[]; // at least 2 images (primary + secondary for hover swap)
colors: { name: string; hex: string }[];
sizes: string[];
description: string; // full description paragraph
details: string[]; // feature list
tags: string[]; // e.g. ["new", "sale", "organic", "gift", "limited"]
material?: string; // material description
fit?: string; // fit description
rating: number; // 0–5
reviewCount: number;
isNew: boolean;
isSale: boolean;
}
AccountPage.tsx, AiConcierge.tsx, products.json, lib/api.ts after generation.edgeone.json with real values, no __SITE_SLUG__ placeholders.__PLACEHOLDER__ tokens must be replaced in every file.The product data file is src/data/products.ts (NOT .json). The products.json template file must be DELETED after generation.
Product data placement:
products: Product[] array using the Product interface defined in the QUALITY FLOOR sectioncategories array with { key, label } — use appropriate labels per categoryPROMO_CODES map with { code, discount, type, description }| Layer | Technology |
|---|---|
| ------------ | ----------------------------------------------------- |
| Frontend | React 18 + Vite 5 + TypeScript 5 + Tailwind CSS 3 |
| Icons | lucide-react (NO emoji) |
| Animation | framer-motion |
| State | Zustand + persist middleware |
| Routing | react-router-dom v6 |
| Fonts | Noto Sans SC (body) + Playfair Display (heading) |
| API | Hono (Edge Functions) + Node Functions |
| Payment | Stripe (mock dev / live prod) |
| Deployment | EdgeOne Pages |
#000 or #fffaspect-square or aspect-[4/5] for product cardsfont-display) for H1/H2, body (font-body) for everything elseAfter scaffolding, always deliver notes in this format:
## Handoff Notes — <Brand> Store
### Scaffold Status
- [x] All 7 routes implemented
- [x] Product data wired (N products)
- [x] Cart with persist middleware
- [x] Mock checkout flow (3-step: address → payment → review)
- [x] AI concierge widget
- [x] Admin dashboard scaffold
- [x] Build passes (tsc + vite build)
- [x] All images verified 200
### Production Wiring Required
- [ ] Connect Stripe live keys (set STRIPE_SECRET_KEY)
- [ ] Wire AI assistant endpoint (set AI_API_KEY, AI_MODEL)
- [ ] Replace mock order IDs with database persistence
- [ ] Set VITE_SITE_NAME, VITE_DEFAULT_CURRENCY in EdgeOne env vars
### Dev Server
npm run dev → http://localhost:5173
npm run build)/product/:id is accessible from ProductCard clicks/shop has filter + sort + grid/list toggletext-[11px], text-[13px], etc.)__PLACEHOLDER__ tokens remain in any file共 2 个版本