c12320cb79
Replace static HTML website with Astro SSG framework: - Astro 6 + React 19 (client islands) + Tailwind CSS 4 + shadcn/ui - i18n: zh/zh_Hant/en with URL prefix routing - Pages: Landing, Features, Pricing, About, Privacy, Terms (3 locales) - Responsive full-width layout with scroll reveal animations - Cyber gradient theme with particle effects inspired by Kimi - Features page: alternating layout with hexagram illustrations - Legal pages: markdown rendering with side info card - Language switcher preserves current page path - Assets shared via symlinks to web/design/assets/ (no duplication) Tech decisions documented in .trellis/spec/web/index.md Task: .trellis/tasks/05-08-web-astro-react-tailwind-shadcn-ui
8.0 KiB
8.0 KiB
Web Development Guidelines
Astro 6 + React 19 + Tailwind CSS 4 + shadcn/ui
Tech Stack
| Layer | Technology | Version |
|---|---|---|
| Framework | Astro | 6.x |
| Interactive UI | React | 19.x (client-only, no RSC) |
| Styling | Tailwind CSS | 4.x (via @tailwindcss/vite) |
| Component Library | shadcn/ui | latest |
| Language | TypeScript | 5.x (strict) |
| i18n | Built-in (type-safe object in src/i18n/utils.ts) |
- |
| Markdown Rendering | marked |
latest |
| Auth | Supabase Auth JS SDK | - |
Architecture Decision
- Astro SSG for marketing/public pages (SEO-critical)
- React client islands for interactive parts (Login, Dashboard, Notifications)
- No React Server Components — CVE-2025-55182 risk eliminated
- No Next.js — multiple critical CVEs (CVE-2025-55182, CVE-2025-29927, CVE-2025-66478)
Actual Dependencies
astro, @astrojs/react, react, react-dom, @tailwindcss/vite, tailwindcss, marked
Pre-Development Checklist
Before writing web code, read:
- This index
- Design file:
web/design/eryao.pen - Backend API contracts:
docs/protocols/ - Error code mapping:
docs/protocols/common/http-error-codes.md - Mobile i18n files (for translation sync):
apps/lib/l10n/app_*.arb
Project Structure
web/
├── design/ # Pencil design files (.pen)
│ ├── eryao.pen
│ └── assets/ # Shared assets (images, legal)
│ ├── images/
│ └── legal/{zh,zh_Hant,en}/
├── public/
│ ├── images -> ../design/assets/images # symlink, no duplication
│ ├── legal -> ../design/assets/legal # symlink, no duplication
│ ├── favicon.ico
│ └── favicon.svg
├── src/
│ ├── components/
│ │ ├── Navbar.astro # Marketing nav (responsive, lang switcher)
│ │ ├── Footer.astro # Marketing footer (responsive)
│ │ ├── Hero.astro # Landing hero section
│ │ ├── Showcase.astro # Landing showcase section
│ │ ├── Testimonials.astro # Landing testimonials section
│ │ ├── CtaSection.astro # Landing CTA section
│ │ ├── FeaturesPage.astro # Features grid page
│ │ ├── PricingPage.astro # Pricing cards page
│ │ ├── AboutPage.astro # About + company info page
│ │ └── LegalPage.astro # Markdown legal page (generic)
│ ├── layouts/
│ │ └── Marketing.astro # Nav + content + footer + scroll animations
│ ├── pages/
│ │ ├── index.astro # Root redirect -> /zh/
│ │ ├── {zh,zh_Hant,en}/
│ │ │ ├── index.astro # Landing
│ │ │ ├── features.astro
│ │ │ ├── pricing.astro
│ │ │ ├── about.astro
│ │ │ ├── privacy.astro
│ │ │ └── terms.astro
│ ├── i18n/
│ │ └── utils.ts # Type-safe translations (all inline)
│ └── styles/
│ ├── global.css # Tailwind entry
│ └── animations.css # Scroll reveal animations
├── astro.config.mjs
├── tsconfig.json
└── package.json
Responsive Layout
All pages must be fully responsive: full-width sections, no fixed pixel widths.
Layout Principles
- Full-width sections — Each section spans
w-full, content is centered withmax-w-7xl mx-auto - No fixed pixel widths — Use
w-full,max-w-*, andflex/gridfor all layouts - Mobile-first — Base styles target mobile,
md:breakpoint for desktop - Viewport-filling sections — Hero and CTA use
min-h-screenor generous padding to fill viewport - Smooth scroll transitions — Each section flows into the next with gradients or color changes
Breakpoints
| Breakpoint | Target |
|---|---|
| Base (< 768px) | Mobile phones |
md: (>= 768px) |
Tablets and desktop |
Section Patterns
Hero: w-full, min-h-screen, bg-gradient, centered content
Showcase: w-full, flex-col md:flex-row, gap, centered max-w
Testimonials: w-full, bg-slate-900, grid cols-1 md:cols-3
CTA: w-full, bg-violet-600, centered
Footer: w-full, bg-slate-950, responsive flex
Design Tokens
All colors from design map directly to Tailwind defaults:
| Token | Tailwind | Hex |
|---|---|---|
| Primary | violet-600 |
#7C3AED |
| Primary light | violet-100 |
— |
| Background | white |
#FFFFFF |
| Surface | slate-50 |
#F8FAFC |
| Dark bg | slate-900 |
#0F172A |
| Footer bg | slate-950 |
#020617 |
| Border | slate-200 |
#E2E8F0 |
| Warning bg | amber-50 |
#FFFBEB |
| Gradient top | white -> violet-50 |
— |
Scroll Animations
Defined in src/styles/animations.css, triggered by IntersectionObserver in Marketing.astro.
| Class | Effect | Use Case |
|---|---|---|
.reveal |
Fade up (translateY 24px) | Default for most elements |
.reveal-left |
Slide from left | Showcase left column |
.reveal-right |
Slide from right | Showcase right column |
.reveal-scale |
Scale in (0.95 -> 1) | CTA section |
.stagger-1 to .stagger-4 |
Delay 0.1s-0.4s | Grouped elements (cards, grid items) |
- All animations:
0.6-0.7s,cubic-bezier(0.22, 1, 0.36, 1)(ease-out-quint) prefers-reduced-motion: reducedisables all animations- Observer
rootMargin: 0px 0px -60px 0pxfor pre-trigger - Elements are
opacity: 0until.visibleclass is added, thenanimation-fill-mode: forwards
i18n (CRITICAL)
Every user-visible text must use i18n keys. No hardcoded strings.
Supported Locales
| Code | Language | Brand Name |
|---|---|---|
zh |
简体中文 | 觅爻签问 |
zh_Hant |
繁體中文 | 覓爻簽問 |
en |
English | MeiYao Divination |
Implementation
- All translations are in
src/i18n/utils.tsas a typedRecord<Locale, Translations>object - Access via
t(locale, 'section')which returns the section object (e.g.,t(locale, 'nav').features) - URL strategy:
/{locale}/pathprefix (e.g.,/zh/,/en/) - Default locale:
zh, root/redirects to/zh/ - Config in
astro.config.mjswithprefixDefaultLocale: true
Rules
- All text must come from
t()— never inline strings - Brand name is always from
footer.brandName(consistent across Navbar/Footer) - Check Flutter i18n first (
apps/lib/l10n/app_*.arb) before inventing translations - Legal content loaded from
public/legal/{locale}/markdown files
Assets
- Shared assets live in
web/design/assets/(used by Pencil) web/public/imagesandweb/public/legalare symlinks to../design/assets/*- Never duplicate assets — always use symlinks or references
Cross-Layer Contracts
API Integration
- Backend: FastAPI REST endpoints (see
docs/protocols/) - Auth: Supabase Auth JS SDK (client-side)
- Error format: RFC 7807
ApiProblem(same as mobile)
Brand Consistency (Flutter app)
- App title: "觅爻签问" / "MeiYao Divination" (NOT "MiYao")
- Company: 洵觅科技(深圳)有限公司 / Xunmee Technology (Shenzhen) Co., Ltd.
- Contact: xuyunlong@xunmee.com
- ICP: 粤ICP备2025428416号-1A
Quality Rules
Forbidden
- Do not use React Server Components (RSC)
- Do not import server-only modules in client islands
- Do not hardcode colors outside Tailwind tokens
- Do not use fixed pixel widths for layout (use responsive utilities)
- Do not use
anyin TypeScript - Do not use third-party shadcn registries (official only)
- Do not duplicate assets — use symlinks
Required
- All pages must be fully responsive (mobile + desktop)
- All sections must be full-width with centered content
- All pages must pass Lighthouse SEO >= 95 (marketing pages)
- All interactive components must be accessible (ARIA)
npm auditmust be clean before merge- TypeScript strict mode enabled
prefers-reduced-motionmust disable animations