Initial commit with translated description

This commit is contained in:
2026-03-29 10:21:57 +08:00
commit 87279e170c
11 changed files with 2625 additions and 0 deletions

116
README.md Normal file
View File

@@ -0,0 +1,116 @@
# Frontend Design Ultimate
🎨 Create distinctive, production-grade static sites with React, Tailwind CSS, and shadcn/ui — no mockups needed.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![ClawHub](https://img.shields.io/badge/ClawHub-frontend--design--ultimate-purple)](https://clawhub.ai/skills/frontend-design-ultimate)
## What is this?
An OpenClaw/Claude Code skill that generates bold, memorable web designs from plain text requirements. No Figma, no wireframes — just describe what you want.
**Key Features:**
- 🚫 **Anti-AI-slop** — Explicit guidance to avoid generic designs (no Inter, no purple gradients, no centered layouts)
- 📱 **Mobile-first patterns** — Responsive CSS that actually works
-**Two workflows** — Vite (pure static) or Next.js (Vercel deploy)
- 🧩 **shadcn/ui components** — 10 common components pre-installed, add more with CLI
- 📦 **Single-file bundling** — Bundle entire sites to one HTML file
## Quick Start
### Install the Skill
```bash
# OpenClaw
openclaw skill install frontend-design-ultimate
# Claude Code (copy to .claude/skills/)
git clone https://github.com/kesslerio/frontend-design-ultimate-clawhub-skill.git ~/.claude/skills/frontend-design-ultimate
```
### Use It
Just describe what you want:
```
Build a SaaS landing page for an AI writing tool. Dark theme,
editorial typography, subtle grain texture. Pages: hero with
animated demo, features grid, pricing table, FAQ accordion, footer.
```
The skill will:
1. Commit to a bold aesthetic direction
2. Choose distinctive typography (no Inter!)
3. Build with React + Tailwind + shadcn/ui
4. Apply mobile-first responsive patterns
5. Output production-ready code
## What Makes This Different?
### vs. Generic AI Design
| Generic AI | This Skill |
|------------|------------|
| Inter font everywhere | Distinctive typography choices |
| Purple gradients | Context-appropriate palettes |
| Centered layouts | Intentional spatial composition |
| No animations | Orchestrated motion |
| Solid backgrounds | Atmospheric textures |
### Based On
- **Anthropic's frontend-design** — Design philosophy, anti-AI-slop guidance
- **Anthropic's web-artifacts-builder** — React+Tailwind+shadcn scaffolding
- **Community frontend-design-v2** — Mobile-first responsive patterns
## Workflows
### Option A: Vite (Pure Static)
```bash
bash scripts/init-vite.sh my-site
cd my-site
npm run dev
# Build
npm run build
# Bundle to single HTML
bash scripts/bundle-artifact.sh
```
### Option B: Next.js (Vercel)
```bash
bash scripts/init-nextjs.sh my-site
cd my-site
npm run dev
# Deploy
vercel
```
## Documentation
- [SKILL.md](SKILL.md) — Main skill instructions
- [references/design-philosophy.md](references/design-philosophy.md) — Anti-AI-slop manifesto
- [references/mobile-patterns.md](references/mobile-patterns.md) — Responsive CSS patterns
- [references/shadcn-components.md](references/shadcn-components.md) — Component quick reference
- [templates/site-config.ts](templates/site-config.ts) — Editable content config example
## Requirements
- Node.js 18+
- npm
## License
Apache 2.0 — See [LICENSE](LICENSE)
## Credits
Built on the shoulders of:
- [Anthropic's Claude Skills](https://github.com/anthropics/skills)
- [shadcn/ui](https://ui.shadcn.com)
- [Tailwind CSS](https://tailwindcss.com)
- [nhatmobile1's frontend-design-v2](https://github.com/nhatmobile1/claude-skills)
---
Made with 🎨 by [Kessler.io](https://kessler.io)

139
REVIEW.md Normal file
View File

@@ -0,0 +1,139 @@
# Skill Review: frontend-design-ultimate
Review Date: 2026-02-01
Reviewer: Niemand Code (automated)
## Source Skill Consistency Check
### 1. Anthropic frontend-design ✅
| Source Requirement | Our Implementation | Status |
|-------------------|-------------------|--------|
| "BOLD aesthetic direction" | SKILL.md:47-70 "Design Thinking" section | ✅ Matches |
| Typography: avoid Inter, Roboto, Arial | SKILL.md:76 "BANNED" list, references/design-philosophy.md:30-47 | ✅ Matches |
| Color: dominant + sharp accents | SKILL.md:96-108 | ✅ Matches |
| Motion: orchestrated page load | SKILL.md:111-120, references/design-philosophy.md:142-170 | ✅ Matches |
| Spatial: asymmetry, overlap | SKILL.md:122-127 | ✅ Matches |
| Backgrounds: atmosphere, textures | SKILL.md:129-145 | ✅ Matches |
| Anti-AI-slop philosophy | Throughout + references/design-philosophy.md | ✅ Matches |
**Consistency: 100%**
### 2. Anthropic web-artifacts-builder ✅
| Source Requirement | Our Implementation | Status |
|-------------------|-------------------|--------|
| React 18 + TypeScript + Vite | scripts/init-vite.sh:15-17 | ✅ Matches |
| Tailwind CSS + shadcn/ui | scripts/init-vite.sh:22-50 | ✅ Matches |
| Path aliases (@/) | scripts/init-vite.sh:176-190 | ✅ Matches |
| 40+ shadcn components | scripts/init-vite.sh:23-47 (manual install) | ⚠️ Partial |
| Parcel bundling | scripts/bundle-artifact.sh | ✅ Matches |
| Single HTML output | scripts/bundle-artifact.sh:44 | ✅ Matches |
**Note on shadcn**: Source uses `npx shadcn@latest add` for all components. Our init-vite.sh manually installs Radix deps but doesn't pre-add all shadcn components. Consider using `npx shadcn@latest add --all`.
**Consistency: 90%**
### 3. Community frontend-design-v2 ✅
| Source Requirement | Our Implementation | Status |
|-------------------|-------------------|--------|
| Hero grid→flex mobile fix | references/mobile-patterns.md:10-55 | ✅ Matches |
| Accordion for large lists | references/mobile-patterns.md:59-105 | ✅ Matches |
| Form element consistency | references/mobile-patterns.md:238-280 | ✅ Matches |
| Breakpoint reference | references/mobile-patterns.md:375-390 | ✅ Matches |
| Pre-implementation checklist | SKILL.md:228-250 | ✅ Matches |
| Color contrast checklist | references/mobile-patterns.md:300-335 | ✅ Matches |
**Consistency: 100%**
---
## Code Quality Issues
### scripts/init-vite.sh
1. **Line 23-47**: Manual Radix UI installation is verbose. Could use:
```bash
npx shadcn@latest init -y
npx shadcn@latest add --all -y
```
2. **Missing error handling**: No check if npm commands fail.
3. **Missing Node version check**: Should verify Node 18+.
### scripts/init-nextjs.sh
1. **Line 25**: Uses `-y` flag which may not be supported by all versions of shadcn CLI.
2. **Hardcoded component list**: Only installs 10 components vs "40+" claimed.
### scripts/bundle-artifact.sh
1. **Good**: Has `set -e` for error handling.
2. **Good**: Checks for package.json and index.html.
3. **Minor**: Could add cleanup of node_modules/.parcel-cache on error.
---
## Gaps & Improvements
### Missing from Source Skills
1. **Testing guidance**: web-artifacts-builder mentions Playwright/Puppeteer testing. We don't.
2. **Motion library**: frontend-design mentions "Motion library for React". We don't specify framer-motion or alternatives.
3. **Node version pinning**: web-artifacts-builder mentions "auto-detects and pins Vite version". Our scripts don't.
### Recommended Additions
1. Add `framer-motion` to dependencies for complex animations.
2. Add `.nvmrc` or `engines` in package.json for Node 18+.
3. Add example components (Hero, Features, Pricing) as templates.
4. Consider adding a `--dark` flag to init scripts for dark-mode-first projects.
---
## ClawHub Publishing Readiness
| Requirement | Status |
|-------------|--------|
| SKILL.md present | ✅ |
| Valid frontmatter | ✅ |
| Description for discovery | ✅ Good keywords |
| LICENSE file | ✅ Apache 2.0 |
| README.md | ✅ |
| No hardcoded secrets | ✅ |
| Scripts executable | ✅ |
**Ready for publishing: YES**
---
## Summary
| Category | Score |
|----------|-------|
| Source consistency | 97% |
| Code quality | 85% |
| Documentation | 95% |
| Publishing readiness | 100% |
**Overall: Ready to publish with minor improvements recommended.**
### Priority Fixes
1. [ ] Fix init-vite.sh to use `npx shadcn@latest add --all` instead of manual Radix installs
2. [ ] Add framer-motion to dependencies
3. [ ] Add Node version check to scripts
### Nice-to-Have
1. [ ] Add example component templates
2. [ ] Add --dark flag for dark-mode-first
3. [ ] Add Playwright testing example

379
SKILL.md Normal file
View File

@@ -0,0 +1,379 @@
---
name: frontend-design-ultimate
description: "使用React、Tailwind CSS和shadcn/ui创建独特的生产级静态站点。"
homepage: https://github.com/kesslerio/frontend-design-ultimate-clawhub-skill
metadata:
openclaw:
emoji: "🎨"
requires:
bins: ["node", "npm"]
---
# Frontend Design Ultimate
Create distinctive, production-grade static sites from text requirements alone. No mockups, no Figma — just describe what you want and get bold, memorable designs.
**Stack**: React 18 + TypeScript + Tailwind CSS + shadcn/ui + Framer Motion
**Output**: Vite (static HTML) or Next.js (Vercel-ready)
## Quick Start
```
"Build a SaaS landing page for an AI writing tool. Dark theme,
editorial typography, subtle grain texture. Pages: hero with
animated demo, features grid, pricing table, FAQ accordion, footer."
```
---
## Design Thinking (Do This First)
Before writing any code, commit to a **BOLD aesthetic direction**:
### 1. Understand Context
- **Purpose**: What problem does this interface solve? Who uses it?
- **Audience**: Developer tools? Consumer app? Enterprise? Creative agency?
- **Constraints**: Performance requirements, accessibility needs, brand guidelines?
### 2. Choose an Extreme Tone
Pick ONE and commit fully — timid designs fail:
| Tone | Characteristics |
|------|-----------------|
| **Brutally Minimal** | Sparse, monochrome, massive typography, raw edges |
| **Maximalist Chaos** | Layered, dense, overlapping elements, controlled disorder |
| **Retro-Futuristic** | Neon accents, geometric shapes, CRT aesthetics |
| **Organic/Natural** | Soft curves, earth tones, hand-drawn elements |
| **Luxury/Refined** | Subtle animations, premium typography, restrained palette |
| **Editorial/Magazine** | Strong grid, dramatic headlines, whitespace as feature |
| **Brutalist/Raw** | Exposed structure, harsh contrasts, anti-design |
| **Art Deco/Geometric** | Gold accents, symmetry, ornate patterns |
| **Soft/Pastel** | Rounded corners, gentle gradients, friendly |
| **Industrial/Utilitarian** | Functional, monospace, data-dense |
### 3. Define the Unforgettable Element
What's the ONE thing someone will remember? A hero animation? Typography treatment? Color combination? Unusual layout?
---
## Aesthetics Guidelines
### Typography — NEVER Generic
**BANNED**: Inter, Roboto, Arial, system fonts, Open Sans
**DO**: Distinctive, characterful choices that elevate the design.
| Use Case | Approach |
|----------|----------|
| Display/Headlines | Bold personality — Clash, Cabinet Grotesk, Satoshi, Space Grotesk (sparingly), Playfair Display |
| Body Text | Refined readability — Instrument Sans, General Sans, Plus Jakarta Sans |
| Monospace/Code | DM Mono, JetBrains Mono, IBM Plex Mono |
| Pairing Strategy | Contrast weights (thin display + bold body), contrast styles (serif + geometric sans) |
**Size Progression**: Use 3x+ jumps, not timid 1.5x increments.
### Color & Theme
**BANNED**: Purple gradients on white, evenly-distributed 5-color palettes
**DO**:
- **Dominant + Sharp Accent**: 70-20-10 rule (primary-secondary-accent)
- **CSS Variables**: `--primary`, `--accent`, `--surface`, `--text`
- **Commit to dark OR light**: Don't hedge with gray middle-grounds
- **High contrast CTAs**: Buttons should pop dramatically
```css
:root {
--bg-primary: #0a0a0a;
--bg-secondary: #141414;
--text-primary: #fafafa;
--text-secondary: #a1a1a1;
--accent: #ff6b35;
--accent-hover: #ff8555;
}
```
### Motion & Animation
**Priority**: One orchestrated page load > scattered micro-interactions
**High-Impact Moments**:
- Staggered hero reveals (`animation-delay`)
- Scroll-triggered section entrances
- Hover states that surprise (scale, color shift, shadow depth)
- Smooth page transitions
**Implementation**:
- CSS-only for simple animations
- Framer Motion for React (pre-installed via init scripts)
- Keep durations 200-400ms (snappy, not sluggish)
### Spatial Composition
**BANNED**: Centered, symmetrical, predictable layouts
**DO**:
- Asymmetry with purpose
- Overlapping elements
- Diagonal flow / grid-breaking
- Generous negative space OR controlled density (pick one)
- Off-grid hero sections
### Backgrounds & Atmosphere
**BANNED**: Solid white/gray backgrounds
**DO**:
- Gradient meshes (subtle, not garish)
- Noise/grain textures (SVG filter or CSS)
- Geometric patterns (dots, lines, shapes)
- Layered transparencies
- Dramatic shadows for depth
- Blur effects for glassmorphism
```css
/* Subtle grain overlay */
.grain::before {
content: '';
position: fixed;
inset: 0;
background: url("data:image/svg+xml,...") repeat;
opacity: 0.03;
pointer-events: none;
}
```
---
## Mobile-First Patterns
See **[references/mobile-patterns.md](references/mobile-patterns.md)** for detailed CSS.
### Critical Rules
| Pattern | Desktop | Mobile Fix |
|---------|---------|------------|
| Hero with hidden visual | 2-column grid | Switch to `display: flex` (not grid) |
| Large selection lists | Horizontal scroll | Accordion with category headers |
| Multi-column forms | Side-by-side | Stack vertically |
| Status/alert cards | Inline | `align-items: center` + `text-align: center` |
| Feature grids | 3-4 columns | Single column |
### Breakpoints
```css
/* Tablet - stack sidebars */
@media (max-width: 1200px) { }
/* Mobile - full single column */
@media (max-width: 768px) { }
/* Small mobile - compact spacing */
@media (max-width: 480px) { }
```
### Font Scaling
```css
@media (max-width: 768px) {
.hero-title { font-size: 32px; } /* from ~48px */
.section-title { font-size: 24px; } /* from ~32px */
.section-subtitle { font-size: 14px; } /* from ~16px */
}
```
---
## Build Workflow
### Option A: Vite (Pure Static)
```bash
# 1. Initialize
bash scripts/init-vite.sh my-site
cd my-site
# 2. Develop
npm run dev
# 3. Build static files
npm run build
# Output: dist/
# 4. Bundle to single HTML (optional)
bash scripts/bundle-artifact.sh
# Output: bundle.html
```
### Option B: Next.js (Vercel Deploy)
```bash
# 1. Initialize
bash scripts/init-nextjs.sh my-site
cd my-site
# 2. Develop
npm run dev
# 3. Deploy to Vercel
vercel
```
---
## Project Structure
### Vite Static
```
my-site/
├── src/
│ ├── components/ # React components
│ ├── lib/ # Utilities, cn()
│ ├── styles/ # Global CSS
│ ├── config/
│ │ └── site.ts # Editable content config
│ ├── App.tsx
│ └── main.tsx
├── index.html
├── tailwind.config.ts
└── package.json
```
### Next.js
```
my-site/
├── app/
│ ├── layout.tsx
│ ├── page.tsx
│ └── privacy/page.tsx
├── components/
├── lib/
├── config/
│ └── site.ts
└── tailwind.config.ts
```
---
## Site Config Pattern
Keep all editable content in one file:
```typescript
// config/site.ts
export const siteConfig = {
name: "Acme AI",
tagline: "Write better, faster",
description: "AI-powered writing assistant",
hero: {
badge: "Now in beta",
title: "Your words,\nsupercharged",
subtitle: "Write 10x faster with AI that understands your style",
cta: { text: "Get Started", href: "/signup" },
secondaryCta: { text: "Watch Demo", href: "#demo" },
},
features: [
{ icon: "Zap", title: "Lightning Fast", description: "..." },
// ...
],
pricing: [
{ name: "Free", price: 0, features: [...] },
{ name: "Pro", price: 19, features: [...], popular: true },
],
faq: [
{ q: "How does it work?", a: "..." },
],
footer: {
links: [...],
social: [...],
}
}
```
---
## Pre-Implementation Checklist
Run this before finalizing any design:
### Design Quality
- [ ] Typography is distinctive (no Inter/Roboto/Arial)
- [ ] Color palette has clear dominant + accent (not evenly distributed)
- [ ] Background has atmosphere (not solid white/gray)
- [ ] At least one memorable/unforgettable element
- [ ] Animations are orchestrated (not scattered)
### Mobile Responsiveness
- [ ] Hero centers on mobile (no empty grid space)
- [ ] All grids collapse to single column
- [ ] Forms stack vertically
- [ ] Large lists use accordion (not horizontal scroll)
- [ ] Font sizes scale down appropriately
### Form Consistency
- [ ] Input, select, textarea all styled consistently
- [ ] Radio/checkbox visible (check transparent-border styles)
- [ ] Dropdown options have readable backgrounds
- [ ] Labels use CSS variables (not hardcoded colors)
### Accessibility
- [ ] Color contrast meets WCAG AA (4.5:1 text, 3:1 UI)
- [ ] Focus states visible
- [ ] Semantic HTML (nav, main, section, article)
- [ ] Alt text for images
- [ ] Keyboard navigation works
---
## shadcn/ui Components
10 common components pre-installed (button, badge, card, accordion, dialog, navigation-menu, tabs, sheet, separator, avatar, alert). Add more with `npx shadcn@latest add [name]` or install all with `npx shadcn@latest add --all`.
See **[references/shadcn-components.md](references/shadcn-components.md)** for full component reference.
Most used for landing pages:
- `Button`, `Badge` — CTAs and labels
- `Card` — Feature cards, pricing tiers
- `Accordion` — FAQ sections
- `Dialog` — Modals, video players
- `NavigationMenu` — Header nav
- `Tabs` — Feature showcases
- `Carousel` — Testimonials
---
## References
- **[references/design-philosophy.md](references/design-philosophy.md)** — Extended anti-AI-slop guidance
- **[references/mobile-patterns.md](references/mobile-patterns.md)** — Detailed responsive CSS
- **[references/shadcn-components.md](references/shadcn-components.md)** — Component quick reference
- **[templates/site-config.ts](templates/site-config.ts)** — Full siteConfig example
---
## Examples
### Prompt → Output
**Input**:
> "Portfolio site for a photographer. Minimal, editorial feel.
> Grid gallery with lightbox, about section, contact form."
**Design Decisions**:
- Tone: Editorial/Magazine
- Typography: Cormorant Garamond (display) + Inter... wait, banned. Plus Jakarta Sans (body)
- Color: Near-black bg (#0c0c0c), warm white text (#f5f5f0), copper accent (#b87333)
- Unforgettable: Full-bleed hero image with text overlay that reveals on scroll
- Motion: Gallery images fade in staggered on scroll
**Output**: Complete Next.js project with responsive gallery, lightbox component, and contact form with validation.
---
*Based on Anthropic's frontend-design, web-artifacts-builder, and community frontend-design-v2 skills.*

6
_meta.json Normal file
View File

@@ -0,0 +1,6 @@
{
"ownerId": "kn7fmw4ybcy50qzp1d2dvb1h517znaes",
"slug": "frontend-design-ultimate",
"version": "1.0.0",
"publishedAt": 1770018489918
}

View File

@@ -0,0 +1,301 @@
# Design Philosophy — Anti-AI-Slop Manifesto
This reference extends the core SKILL.md with deeper guidance on creating distinctive designs.
## The Problem: AI Slop
Generic AI-generated designs share these telltale signs:
### Typography Sins
- Inter, Roboto, Arial everywhere
- Timid weight ranges (400-600 only)
- Minimal size progression (1.25x-1.5x)
- No distinctive pairing strategy
### Color Crimes
- Purple/blue gradient on white (the cardinal sin)
- 5+ evenly-distributed colors with no hierarchy
- Muted, "safe" palettes that offend no one and delight no one
- Gray backgrounds that signal "I gave up"
### Layout Laziness
- Everything centered
- Perfectly symmetrical
- Predictable card grids
- No visual tension or interest
### Motion Mediocrity
- No animations at all, OR
- Generic fade-in on every element
- No orchestration or timing consideration
### Background Boredom
- Solid white
- Solid light gray
- Maybe a subtle gradient if feeling "bold"
---
## The Solution: Intentional Design
### Commit to an Extreme
The middle ground is where designs go to die. Pick a direction and push it:
**Maximalism Done Right**:
- Dense, layered compositions
- Overlapping elements with clear hierarchy
- Rich textures and patterns
- Multiple animations coordinated
- Every pixel working
**Minimalism Done Right**:
- Extreme restraint (3 colors max)
- Typography as the star
- Negative space as intentional element
- Single, perfect animation
- Nothing extraneous
Both require courage. Both create memorable designs.
### Typography as Identity
Typography isn't decoration — it's the voice of the design.
**Building a Type Hierarchy**:
```css
/* Display: Make a statement */
.display {
font-family: 'Clash Display', sans-serif;
font-size: clamp(3rem, 8vw, 6rem);
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1;
}
/* Heading: Support the display */
.heading {
font-family: 'Satoshi', sans-serif;
font-size: clamp(1.5rem, 3vw, 2.5rem);
font-weight: 500;
letter-spacing: -0.01em;
line-height: 1.2;
}
/* Body: Effortless reading */
.body {
font-family: 'Plus Jakarta Sans', sans-serif;
font-size: 1rem;
font-weight: 400;
line-height: 1.6;
}
/* Mono: Technical credibility */
.mono {
font-family: 'JetBrains Mono', monospace;
font-size: 0.875rem;
letter-spacing: 0;
}
```
**Font Pairing Strategies**:
| Strategy | Display | Body | Effect |
|----------|---------|------|--------|
| Contrast | Serif (Playfair) | Sans (Inter... no, Plus Jakarta) | Editorial elegance |
| Harmony | Geometric (Satoshi) | Geometric (General Sans) | Modern consistency |
| Tension | Brutalist (Clash) | Humanist (Source Sans) | Edgy but readable |
| Technical | Mono (JetBrains) | Sans (IBM Plex Sans) | Developer-focused |
### Color as Emotion
Color isn't about "what looks nice" — it's about what the design FEELS.
**Building a Palette**:
```css
/* Dark, Confident, Premium */
:root {
--bg-primary: #0a0a0a;
--bg-secondary: #171717;
--bg-tertiary: #262626;
--text-primary: #fafafa;
--text-secondary: #a3a3a3;
--accent: #22c55e; /* Confident green */
--accent-subtle: rgba(34, 197, 94, 0.1);
}
/* Light, Warm, Approachable */
:root {
--bg-primary: #fffbf5;
--bg-secondary: #fff7ed;
--bg-tertiary: #ffedd5;
--text-primary: #1c1917;
--text-secondary: #78716c;
--accent: #ea580c; /* Warm orange */
--accent-subtle: rgba(234, 88, 12, 0.1);
}
/* High Contrast, Editorial */
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #000000;
--text-secondary: #525252;
--accent: #dc2626; /* Bold red */
--accent-subtle: rgba(220, 38, 38, 0.05);
}
```
**The 60-30-10 Rule**:
- 60% dominant (background)
- 30% secondary (cards, sections)
- 10% accent (CTAs, highlights)
### Motion as Narrative
Animation tells a story. What's your story?
**Page Load Orchestration**:
```css
/* Hero elements enter in sequence */
.hero-badge {
animation: fadeSlideUp 0.6s ease-out 0.1s both;
}
.hero-title {
animation: fadeSlideUp 0.6s ease-out 0.2s both;
}
.hero-subtitle {
animation: fadeSlideUp 0.6s ease-out 0.3s both;
}
.hero-cta {
animation: fadeSlideUp 0.6s ease-out 0.4s both;
}
@keyframes fadeSlideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
```
**Scroll-Triggered Reveals**:
```javascript
// Intersection Observer for scroll animations
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
```
**Hover States That Surprise**:
```css
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow:
0 20px 40px rgba(0, 0, 0, 0.1),
0 0 0 1px rgba(255, 255, 255, 0.05);
}
/* Or more dramatic */
.card:hover {
transform: scale(1.02) rotate(-0.5deg);
}
```
### Backgrounds as Atmosphere
The background sets the mood before any content is read.
**Gradient Mesh**:
```css
.gradient-mesh {
background:
radial-gradient(at 40% 20%, hsla(28, 100%, 74%, 0.3) 0px, transparent 50%),
radial-gradient(at 80% 0%, hsla(189, 100%, 56%, 0.2) 0px, transparent 50%),
radial-gradient(at 0% 50%, hsla(355, 100%, 93%, 0.3) 0px, transparent 50%),
radial-gradient(at 80% 50%, hsla(340, 100%, 76%, 0.2) 0px, transparent 50%),
radial-gradient(at 0% 100%, hsla(269, 100%, 77%, 0.3) 0px, transparent 50%);
}
```
**Noise Texture**:
```css
.noise::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
opacity: 0.03;
pointer-events: none;
z-index: 1000;
}
```
**Dot Pattern**:
```css
.dots {
background-image: radial-gradient(circle, #333 1px, transparent 1px);
background-size: 20px 20px;
}
```
**Glassmorphism**:
```css
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
```
---
## Design Decision Framework
When stuck, ask these questions:
1. **What's the ONE thing?** — If users remember one element, what is it?
2. **Would I screenshot this?** — Is there a moment worth sharing?
3. **Does it feel designed?** — Or does it feel generated?
4. **What's the emotion?** — Confident? Playful? Serious? Luxurious?
5. **Is it brave?** — Did I play it safe or commit to a direction?
---
## Anti-Pattern Detection
Before shipping, scan for these:
| Anti-Pattern | Fix |
|--------------|-----|
| Inter font | Replace with distinctive alternative |
| Purple gradient | Choose contextual palette |
| All centered | Add asymmetry or left-align |
| No animations | Add orchestrated page load |
| Solid background | Add texture, gradient, or pattern |
| Evenly spaced colors | Apply 60-30-10 rule |
| Generic cards | Add unique styling treatment |
| Default shadows | Use layered, atmospheric shadows |
---
*Remember: Claude is capable of extraordinary creative work. Don't hold back.*

View File

@@ -0,0 +1,519 @@
# Mobile-First Patterns
Comprehensive responsive CSS patterns learned from real-world implementation failures.
## Hero Sections
### Problem
2-column grid layouts leave empty space when one column is hidden on mobile.
### Solution
Switch from `display: grid` to `display: flex` on mobile.
```css
/* Desktop: 2-column grid */
.hero {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 64px;
align-items: center;
padding: 80px 0;
}
/* Mobile: Centered flex */
@media (max-width: 768px) {
.hero {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 40px 20px;
gap: 24px;
}
.hero-content {
align-items: center;
}
.hero-badge {
align-self: center;
}
.hero-title {
font-size: 32px;
text-align: center;
}
.hero-subtitle {
font-size: 14px;
text-align: center;
}
.hero-cta {
flex-direction: column;
align-items: center;
width: 100%;
}
.hero-cta .btn {
width: 100%;
max-width: 280px;
}
.hero-visual {
display: none;
}
}
```
**Key Rule**: Grid reserves space for hidden columns. Flex doesn't.
---
## Large Selection Lists
### Problem
Horizontal scroll for 20+ items is unusable on mobile — text gets cut off.
### Solution
Collapsible accordion with category headers.
```tsx
function MobileSelector({ categories }) {
const [expanded, setExpanded] = useState<string | null>(null);
return (
<div className="selector">
{categories.map(cat => (
<div
key={cat.name}
className={cn("category", expanded === cat.name && "expanded")}
>
<button
className="category-header"
onClick={() => setExpanded(
expanded === cat.name ? null : cat.name
)}
>
<span>{cat.name}</span>
<ChevronDown className={cn(
"transition-transform",
expanded === cat.name && "rotate-180"
)} />
</button>
<div className="category-items">
{cat.items.map(item => (
<button key={item.id} className="item">
{item.name}
</button>
))}
</div>
</div>
))}
</div>
);
}
```
```css
.category-items {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
@media (max-width: 768px) {
.category-items {
display: none;
}
.category.expanded .category-items {
display: flex;
flex-direction: column;
padding: 12px;
background: var(--bg-secondary);
border-radius: 8px;
}
}
```
---
## Form Layouts
### Problem
Multi-column form layouts get cut off on mobile.
### Solution
Stack vertically with full width.
```css
.form-row {
display: flex;
gap: 16px;
}
.form-group {
flex: 1;
}
@media (max-width: 768px) {
.form-row {
flex-direction: column;
}
.form-group {
width: 100%;
}
.form-row.half-width {
/* Even "half width" fields go full on mobile */
flex-direction: column;
}
}
```
---
## Status/Alert Cards
### Problem
Inconsistent text alignment when stacking horizontal elements vertically.
### Solution
Both `align-items: center` AND `text-align: center`.
```css
.alert {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px;
border-radius: 8px;
}
.alert-icon {
flex-shrink: 0;
}
.alert-content {
flex: 1;
}
@media (max-width: 768px) {
.alert {
flex-direction: column;
align-items: center; /* Center flex items */
text-align: center; /* Center text within items */
gap: 8px;
}
.alert-content {
text-align: center; /* Explicit for nested elements */
}
.alert strong {
text-align: center; /* Block elements need explicit */
}
}
```
**Key Rule**: Stacked flex items need BOTH `align-items: center` AND `text-align: center`.
---
## Grid Layouts
### Universal Mobile Collapse
```css
.pricing-grid,
.feature-grid,
.team-grid,
.stats-grid,
.testimonial-grid {
display: grid;
gap: 24px;
}
/* Desktop configurations */
.pricing-grid { grid-template-columns: repeat(3, 1fr); }
.feature-grid { grid-template-columns: repeat(3, 1fr); }
.team-grid { grid-template-columns: repeat(4, 1fr); }
.stats-grid { grid-template-columns: repeat(4, 1fr); }
.testimonial-grid { grid-template-columns: repeat(2, 1fr); }
/* Tablet */
@media (max-width: 1024px) {
.team-grid { grid-template-columns: repeat(2, 1fr); }
.stats-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Mobile: Everything single column */
@media (max-width: 768px) {
.pricing-grid,
.feature-grid,
.team-grid,
.stats-grid,
.testimonial-grid {
grid-template-columns: 1fr;
}
}
```
---
## Navigation
### Mobile Menu Pattern
```tsx
function MobileNav() {
const [open, setOpen] = useState(false);
return (
<>
{/* Mobile menu button */}
<button
className="md:hidden"
onClick={() => setOpen(!open)}
>
{open ? <X /> : <Menu />}
</button>
{/* Mobile menu overlay */}
<div className={cn(
"fixed inset-0 bg-black/50 md:hidden transition-opacity",
open ? "opacity-100" : "opacity-0 pointer-events-none"
)} onClick={() => setOpen(false)} />
{/* Mobile menu panel */}
<nav className={cn(
"fixed top-0 right-0 h-full w-64 bg-background p-6",
"transform transition-transform md:hidden",
open ? "translate-x-0" : "translate-x-full"
)}>
{/* Nav items */}
</nav>
</>
);
}
```
---
## Form Element Consistency
### Always Style as a Group
```css
/* WRONG - Only targets input */
.input {
border: 2px solid var(--border);
border-radius: 8px;
}
/* CORRECT - All form fields */
.input,
.select,
.textarea {
border: 2px solid var(--border);
border-radius: 8px;
padding: 12px 16px;
font-size: 16px; /* Prevents iOS zoom */
background: var(--bg-secondary);
color: var(--text-primary);
}
```
### Textarea Border Radius Exception
Pill-shaped inputs look wrong on textareas:
```css
.input,
.select {
border-radius: 100px; /* Pill shape */
}
.textarea {
border-radius: 16px; /* Softer, but not pill */
}
```
### Dropdown Option Styling
`<option>` elements can't inherit backdrop-filter:
```css
.select {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
color: white;
}
/* Options need solid backgrounds */
.select option {
background: #1a1a2e;
color: white;
}
```
### Prevent iOS Zoom on Focus
iOS zooms on inputs with font-size < 16px:
```css
input, select, textarea {
font-size: 16px; /* Minimum to prevent zoom */
}
/* Or use transform trick */
@media (max-width: 768px) {
input, select, textarea {
font-size: 16px;
}
}
```
---
## Color Contrast Checklist
### Badge/Pill Elements
```css
/* WRONG - May be invisible */
.badge {
background: var(--accent);
color: white; /* Might not contrast */
}
/* CORRECT - Ensure contrast */
.badge {
background: var(--accent);
color: var(--accent-foreground); /* Defined to contrast */
}
```
### Color Swatches
Swatches showing colors need visible borders:
```css
.color-swatch {
border: 2px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}
```
### Dark Theme Form Labels
```css
/* WRONG - Hardcoded */
.label {
color: white;
}
/* CORRECT - Semantic variable */
.label {
color: var(--text-primary);
}
```
---
## Breakpoint Reference
```css
/* Large Desktop */
@media (min-width: 1440px) {
.container { max-width: 1280px; }
}
/* Desktop */
@media (max-width: 1200px) {
/* Stack sidebars, maintain content width */
}
/* Tablet */
@media (max-width: 1024px) {
/* Reduce grid columns */
}
/* Mobile */
@media (max-width: 768px) {
/* Full single-column, centered content */
}
/* Small Mobile */
@media (max-width: 480px) {
/* Compact spacing, reduced font sizes */
}
```
---
## Mobile Font Scaling
```css
/* Base (desktop) */
.display { font-size: 64px; }
.h1 { font-size: 48px; }
.h2 { font-size: 36px; }
.h3 { font-size: 24px; }
.body { font-size: 16px; }
.small { font-size: 14px; }
/* Mobile */
@media (max-width: 768px) {
.display { font-size: 40px; }
.h1 { font-size: 32px; }
.h2 { font-size: 24px; }
.h3 { font-size: 20px; }
.body { font-size: 16px; } /* Keep readable */
.small { font-size: 13px; }
}
```
---
## Touch Target Sizes
Minimum 44x44px for touch targets (Apple HIG):
```css
.btn,
.nav-link,
.icon-btn {
min-height: 44px;
min-width: 44px;
}
@media (max-width: 768px) {
.btn {
padding: 14px 24px; /* Larger touch area */
}
}
```
---
## Pre-Implementation Checklist
Before finalizing any mobile design:
- [ ] Hero centers on mobile (not left-aligned with empty space)
- [ ] All form fields (input, select, textarea) styled consistently
- [ ] Radio/checkboxes visible (especially transparent-border styles)
- [ ] Dropdown options have readable backgrounds
- [ ] Labels use semantic color variables
- [ ] Status/alert cards center properly
- [ ] Large selection lists use accordion (not horizontal scroll)
- [ ] Grid layouts collapse to single column
- [ ] Badge/pill text contrasts with background
- [ ] Color swatches have visible borders
- [ ] Touch targets are 44x44px minimum
- [ ] Font sizes are 16px+ to prevent iOS zoom
- [ ] Navigation has mobile menu pattern

View File

@@ -0,0 +1,342 @@
# shadcn/ui Component Reference
Quick reference for the 40+ pre-installed shadcn/ui components.
Documentation: https://ui.shadcn.com/docs/components
## Most Used for Landing Pages
| Component | Use Case | Example |
|-----------|----------|---------|
| `Button` | CTAs, actions | Hero buttons, form submits |
| `Badge` | Labels, status | "New", "Popular", "Beta" |
| `Card` | Content containers | Feature cards, pricing tiers |
| `Accordion` | Collapsible content | FAQ sections |
| `Dialog` | Modals | Video players, signup forms |
| `NavigationMenu` | Header navigation | Main nav with dropdowns |
| `Tabs` | Tabbed content | Feature showcases |
| `Carousel` | Sliding content | Testimonials, galleries |
## Full Component List
### Layout & Navigation
- `Accordion` — Collapsible sections
- `Breadcrumb` — Navigation trail
- `Carousel` — Sliding content
- `Collapsible` — Expand/collapse
- `NavigationMenu` — Header nav with dropdowns
- `Pagination` — Page navigation
- `Resizable` — Resizable panels
- `Scroll-Area` — Custom scrollbars
- `Separator` — Visual divider
- `Sheet` — Slide-out panels
- `Sidebar` — App sidebars
- `Tabs` — Tabbed content
### Data Display
- `Avatar` — User images
- `Badge` — Labels and status
- `Card` — Content container
- `HoverCard` — Hover popups
- `Table` — Data tables
### Forms
- `Button` — Actions
- `Checkbox` — Multi-select
- `Combobox` — Searchable select
- `DatePicker` — Date selection
- `Form` — Form wrapper with validation
- `Input` — Text input
- `InputOTP` — One-time password
- `Label` — Form labels
- `RadioGroup` — Single select
- `Select` — Dropdown select
- `Slider` — Range selection
- `Switch` — Toggle
- `Textarea` — Multi-line input
- `Toggle` — Toggle button
- `ToggleGroup` — Button group
### Feedback
- `Alert` — Info messages
- `AlertDialog` — Confirmation dialogs
- `Dialog` — Modal windows
- `Drawer` — Bottom sheets
- `Popover` — Popup content
- `Progress` — Loading bars
- `Skeleton` — Loading placeholders
- `Sonner` — Toast notifications
- `Toast` — Notifications
- `Tooltip` — Hover hints
### Utilities
- `AspectRatio` — Maintain ratios
- `Calendar` — Date display
- `Chart` — Data visualization
- `Command` — Command palette
- `ContextMenu` — Right-click menus
- `DropdownMenu` — Dropdown menus
- `Menubar` — App menubars
---
## Code Examples
### Hero with Badge and Buttons
```tsx
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
function Hero() {
return (
<section className="py-24 text-center">
<Badge variant="secondary" className="mb-4">
Now in beta
</Badge>
<h1 className="text-5xl font-bold mb-6">
Your headline here
</h1>
<p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto">
Subheadline with more details about your product.
</p>
<div className="flex gap-4 justify-center">
<Button size="lg">Get Started</Button>
<Button size="lg" variant="outline">Learn More</Button>
</div>
</section>
)
}
```
### Feature Cards
```tsx
import { Card, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Zap, Shield, Globe } from "lucide-react"
const features = [
{ icon: Zap, title: "Fast", description: "Lightning quick performance" },
{ icon: Shield, title: "Secure", description: "Enterprise-grade security" },
{ icon: Globe, title: "Global", description: "CDN in 200+ locations" },
]
function Features() {
return (
<section className="py-24">
<div className="grid md:grid-cols-3 gap-8">
{features.map((f) => (
<Card key={f.title}>
<CardHeader>
<f.icon className="h-10 w-10 mb-4 text-primary" />
<CardTitle>{f.title}</CardTitle>
<CardDescription>{f.description}</CardDescription>
</CardHeader>
</Card>
))}
</div>
</section>
)
}
```
### Pricing Table
```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Check } from "lucide-react"
const plans = [
{ name: "Free", price: 0, features: ["5 projects", "Basic support"] },
{ name: "Pro", price: 19, features: ["Unlimited projects", "Priority support", "API access"], popular: true },
{ name: "Team", price: 49, features: ["Everything in Pro", "Team features", "SSO"] },
]
function Pricing() {
return (
<section className="py-24">
<div className="grid md:grid-cols-3 gap-8">
{plans.map((plan) => (
<Card key={plan.name} className={plan.popular ? "border-primary" : ""}>
<CardHeader>
{plan.popular && <Badge className="w-fit mb-2">Most Popular</Badge>}
<CardTitle>{plan.name}</CardTitle>
<CardDescription>
<span className="text-4xl font-bold">${plan.price}</span>
<span className="text-muted-foreground">/month</span>
</CardDescription>
</CardHeader>
<CardContent>
<ul className="space-y-2">
{plan.features.map((f) => (
<li key={f} className="flex items-center gap-2">
<Check className="h-4 w-4 text-primary" />
{f}
</li>
))}
</ul>
</CardContent>
<CardFooter>
<Button className="w-full" variant={plan.popular ? "default" : "outline"}>
Get Started
</Button>
</CardFooter>
</Card>
))}
</div>
</section>
)
}
```
### FAQ Accordion
```tsx
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
const faqs = [
{ q: "How does it work?", a: "Our platform uses AI to..." },
{ q: "Is there a free trial?", a: "Yes, you get 14 days free..." },
{ q: "Can I cancel anytime?", a: "Absolutely, no questions asked..." },
]
function FAQ() {
return (
<section className="py-24 max-w-3xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">
Frequently Asked Questions
</h2>
<Accordion type="single" collapsible>
{faqs.map((faq, i) => (
<AccordionItem key={i} value={`item-${i}`}>
<AccordionTrigger>{faq.q}</AccordionTrigger>
<AccordionContent>{faq.a}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</section>
)
}
```
### Mobile Navigation with Sheet
```tsx
import { Button } from "@/components/ui/button"
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
import { Menu } from "lucide-react"
function MobileNav() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden">
<Menu className="h-6 w-6" />
</Button>
</SheetTrigger>
<SheetContent side="right">
<nav className="flex flex-col gap-4 mt-8">
<a href="#features">Features</a>
<a href="#pricing">Pricing</a>
<a href="#faq">FAQ</a>
<Button className="mt-4">Get Started</Button>
</nav>
</SheetContent>
</Sheet>
)
}
```
### Video Modal with Dialog
```tsx
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Play } from "lucide-react"
function VideoModal() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" size="lg">
<Play className="mr-2 h-4 w-4" />
Watch Demo
</Button>
</DialogTrigger>
<DialogContent className="max-w-4xl p-0">
<div className="aspect-video">
<iframe
src="https://www.youtube.com/embed/..."
className="w-full h-full"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
</DialogContent>
</Dialog>
)
}
```
---
## Styling Tips
### Customizing Colors
shadcn uses CSS variables. Override in your globals.css:
```css
:root {
--primary: 220 90% 56%;
--primary-foreground: 0 0% 100%;
--accent: 25 95% 53%;
}
.dark {
--primary: 220 90% 66%;
}
```
### Extending Variants
```tsx
// components/ui/button.tsx
const buttonVariants = cva(
"...",
{
variants: {
variant: {
default: "...",
// Add custom variant
gradient: "bg-gradient-to-r from-primary to-accent text-white hover:opacity-90",
},
},
}
)
```
### Using with Tailwind
All components accept `className` for additional styling:
```tsx
<Button className="rounded-full px-8">
Pill Button
</Button>
<Card className="bg-gradient-to-br from-primary/10 to-accent/10">
Gradient Card
</Card>
```

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# Bundle a Vite React project into a single HTML file
# Usage: bash scripts/bundle-artifact.sh
# Run from project root (where package.json is)
set -e
echo "📦 Bundling to single HTML file..."
# Check if we're in a project directory
if [ ! -f "package.json" ]; then
echo "❌ Error: No package.json found. Run this from your project root."
exit 1
fi
# Check if index.html exists
if [ ! -f "index.html" ]; then
echo "❌ Error: No index.html found in project root."
exit 1
fi
# Install bundling dependencies if needed
if ! npm ls parcel > /dev/null 2>&1; then
echo "📦 Installing bundling dependencies..."
npm install -D parcel @parcel/config-default parcel-resolver-tspaths html-inline
fi
# Create .parcelrc if it doesn't exist
if [ ! -f ".parcelrc" ]; then
echo "⚙️ Creating Parcel config..."
cat > .parcelrc << 'EOF'
{
"extends": "@parcel/config-default",
"resolvers": ["parcel-resolver-tspaths", "..."]
}
EOF
fi
# Build with Parcel
echo "🔨 Building with Parcel..."
npx parcel build index.html --no-source-maps --dist-dir dist-parcel
# Inline all assets
echo "📄 Inlining assets into single HTML..."
npx html-inline -i dist-parcel/index.html -o bundle.html -b dist-parcel
# Clean up
rm -rf dist-parcel .parcel-cache
# Get file size
SIZE=$(ls -lh bundle.html | awk '{print $5}')
echo ""
echo "✅ Bundle created: bundle.html ($SIZE)"
echo ""
echo "You can now share this file or use it as a Claude artifact."
echo ""

154
scripts/init-nextjs.sh Normal file
View File

@@ -0,0 +1,154 @@
#!/bin/bash
# Initialize a Next.js + TypeScript + Tailwind + shadcn/ui project
# Usage: bash scripts/init-nextjs.sh <project-name>
set -e
PROJECT_NAME="${1:-my-site}"
# Check Node version
NODE_VERSION=$(node -v 2>/dev/null | cut -d'v' -f2 | cut -d'.' -f1)
if [ -z "$NODE_VERSION" ] || [ "$NODE_VERSION" -lt 18 ]; then
echo "❌ Error: Node.js 18+ is required. Current: $(node -v 2>/dev/null || echo 'not installed')"
exit 1
fi
echo "🚀 Creating Next.js project: $PROJECT_NAME"
# Create Next.js project with all options
npx create-next-app@latest "$PROJECT_NAME" \
--typescript \
--tailwind \
--eslint \
--app \
--src-dir \
--import-alias "@/*"
cd "$PROJECT_NAME"
# Create .nvmrc for Node version
echo "18" > .nvmrc
echo "📦 Installing additional dependencies..."
# Install animation library
npm install framer-motion
# Install shadcn/ui
echo "📦 Initializing shadcn/ui..."
npx shadcn@latest init -y -d
# Install common components
echo "📦 Installing common components..."
npx shadcn@latest add button badge card accordion dialog navigation-menu tabs sheet separator avatar alert -y || {
echo "⚠️ Warning: Some shadcn components may not have installed. Run 'npx shadcn@latest add [name]' manually."
}
# Install lucide icons
npm install lucide-react
# Create config directory
mkdir -p src/config
# Create site config
cat > src/config/site.ts << 'EOF'
export const siteConfig = {
name: "My Site",
tagline: "Build something amazing",
description: "A modern website built with Next.js, Tailwind, and shadcn/ui",
url: "https://mysite.com",
nav: {
links: [
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "FAQ", href: "#faq" },
],
cta: { label: "Get Started", href: "/signup" },
},
// Add more sections as needed
}
export type SiteConfig = typeof siteConfig
EOF
# Update globals.css with custom animations
cat >> src/app/globals.css << 'EOF'
/* Custom animations */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in {
animation: fade-in 0.5s ease-out;
}
.animate-slide-up {
animation: slide-up 0.5s ease-out;
}
/* Staggered animations */
.stagger-1 { animation-delay: 0.1s; }
.stagger-2 { animation-delay: 0.2s; }
.stagger-3 { animation-delay: 0.3s; }
.stagger-4 { animation-delay: 0.4s; }
.stagger-5 { animation-delay: 0.5s; }
EOF
# Create a basic page with animation example
cat > src/app/page.tsx << 'EOF'
import { Button } from "@/components/ui/button"
import { siteConfig } from "@/config/site"
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-center p-24">
<h1 className="text-5xl font-bold mb-4 animate-slide-up">
{siteConfig.name}
</h1>
<p className="text-xl text-muted-foreground mb-8 animate-slide-up stagger-1">
{siteConfig.tagline}
</p>
<Button size="lg" className="animate-slide-up stagger-2">
Get Started
</Button>
</main>
)
}
EOF
echo ""
echo "✅ Next.js project created successfully!"
echo ""
echo "Installed:"
echo " ✓ Next.js 14+ with App Router"
echo " ✓ TypeScript + Tailwind CSS"
echo " ✓ shadcn/ui with 10 components"
echo " ✓ Framer Motion for animations"
echo " ✓ Site config pattern"
echo ""
echo "Next steps:"
echo " cd $PROJECT_NAME"
echo " npm run dev"
echo ""
echo "Add more components:"
echo " npx shadcn@latest add [component-name]"
echo " npx shadcn@latest add --all # Install all components"
echo ""
echo "Deploy to Vercel:"
echo " vercel"
echo ""

357
scripts/init-vite.sh Normal file
View File

@@ -0,0 +1,357 @@
#!/bin/bash
# Initialize a Vite + React + TypeScript + Tailwind + shadcn/ui project
# Usage: bash scripts/init-vite.sh <project-name>
set -e
PROJECT_NAME="${1:-my-site}"
# Check Node version
NODE_VERSION=$(node -v 2>/dev/null | cut -d'v' -f2 | cut -d'.' -f1)
if [ -z "$NODE_VERSION" ] || [ "$NODE_VERSION" -lt 18 ]; then
echo "❌ Error: Node.js 18+ is required. Current: $(node -v 2>/dev/null || echo 'not installed')"
exit 1
fi
echo "🚀 Creating Vite project: $PROJECT_NAME"
# Create Vite project
npm create vite@latest "$PROJECT_NAME" -- --template react-ts
cd "$PROJECT_NAME"
# Create .nvmrc for Node version
echo "18" > .nvmrc
echo "📦 Installing dependencies..."
# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# Install animation library
npm install framer-motion
# Install shadcn/ui base dependencies
npm install tailwindcss-animate class-variance-authority clsx tailwind-merge
npm install lucide-react
npm install @radix-ui/react-slot
echo "⚙️ Configuring Tailwind..."
# Create tailwind.config.ts
cat > tailwind.config.ts << 'EOF'
import type { Config } from "tailwindcss"
import { fontFamily } from "tailwindcss/defaultTheme"
import tailwindcssAnimate from "tailwindcss-animate"
const config: Config = {
darkMode: ["class"],
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [tailwindcssAnimate],
}
export default config
EOF
# Create base CSS
cat > src/index.css << 'EOF'
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
EOF
# Create utils
mkdir -p src/lib
cat > src/lib/utils.ts << 'EOF'
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
EOF
# Create components directory
mkdir -p src/components/ui
# Create Button component
cat > src/components/ui/button.tsx << 'EOF'
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
EOF
# Update vite.config.ts with path aliases
cat > vite.config.ts << 'EOF'
import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
EOF
# Update tsconfig.json
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
EOF
# Create components.json for shadcn CLI
cat > components.json << 'EOF'
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
EOF
echo ""
echo "📦 Installing shadcn/ui components..."
# Install common components via shadcn CLI
npx shadcn@latest add button badge card accordion dialog navigation-menu tabs sheet separator avatar alert -y || {
echo "⚠️ Warning: Some shadcn components may not have installed. Run 'npx shadcn@latest add [name]' manually."
}
echo ""
echo "✅ Project created successfully!"
echo ""
echo "Installed:"
echo " ✓ React 18 + TypeScript + Vite"
echo " ✓ Tailwind CSS with shadcn/ui theming"
echo " ✓ Framer Motion for animations"
echo " ✓ 10 shadcn/ui components (add more with: npx shadcn@latest add [component])"
echo " ✓ Path aliases (@/) configured"
echo ""
echo "Next steps:"
echo " cd $PROJECT_NAME"
echo " npm run dev"
echo ""
echo "Add more components:"
echo " npx shadcn@latest add [component-name]"
echo " npx shadcn@latest add --all # Install all components"
echo ""
echo "Build for production:"
echo " npm run build"
echo ""

255
templates/site-config.ts Normal file
View File

@@ -0,0 +1,255 @@
/**
* Site Configuration
*
* All editable content in one place. Update this file to change
* text, links, and content throughout the site.
*/
export const siteConfig = {
// === Meta ===
name: "Acme AI",
tagline: "Write better, faster",
description: "AI-powered writing assistant that adapts to your style",
url: "https://acme.ai",
// === Navigation ===
nav: {
links: [
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "FAQ", href: "#faq" },
{ label: "Blog", href: "/blog" },
],
cta: { label: "Get Started", href: "/signup" },
},
// === Hero Section ===
hero: {
badge: "Now in public beta",
title: "Your words,\nsupercharged",
subtitle: "Write 10x faster with AI that learns your style. No more staring at blank pages.",
cta: {
primary: { label: "Start Free Trial", href: "/signup" },
secondary: { label: "Watch Demo", href: "#demo" },
},
// Optional: stats under hero
stats: [
{ value: "50K+", label: "Active users" },
{ value: "2M+", label: "Words written" },
{ value: "4.9", label: "App Store rating" },
],
},
// === Social Proof ===
socialProof: {
title: "Trusted by teams at",
logos: [
{ name: "Vercel", src: "/logos/vercel.svg" },
{ name: "Stripe", src: "/logos/stripe.svg" },
{ name: "Notion", src: "/logos/notion.svg" },
{ name: "Linear", src: "/logos/linear.svg" },
{ name: "Figma", src: "/logos/figma.svg" },
],
},
// === Features Section ===
features: {
title: "Everything you need to write better",
subtitle: "Powerful features that adapt to your workflow",
items: [
{
icon: "Zap",
title: "Lightning Fast",
description: "Get suggestions in milliseconds, not seconds. Built on cutting-edge infrastructure.",
},
{
icon: "Brain",
title: "Learns Your Style",
description: "The more you write, the better it gets. Your voice, amplified.",
},
{
icon: "Shield",
title: "Private by Default",
description: "Your data stays yours. We never train on your content.",
},
{
icon: "Globe",
title: "Works Everywhere",
description: "Browser extension, desktop app, and API. Write anywhere.",
},
{
icon: "Sparkles",
title: "Smart Suggestions",
description: "Context-aware completions that actually make sense.",
},
{
icon: "Users",
title: "Team Collaboration",
description: "Share styles across your team for consistent voice.",
},
],
},
// === Pricing Section ===
pricing: {
title: "Simple, transparent pricing",
subtitle: "Start free, upgrade when you need more",
plans: [
{
name: "Free",
price: 0,
period: "forever",
description: "Perfect for trying it out",
features: [
"500 suggestions/month",
"Browser extension",
"Basic style learning",
],
cta: { label: "Get Started", href: "/signup" },
},
{
name: "Pro",
price: 19,
period: "/month",
description: "For serious writers",
features: [
"Unlimited suggestions",
"All platforms",
"Advanced style learning",
"Priority support",
"API access",
],
cta: { label: "Start Free Trial", href: "/signup?plan=pro" },
popular: true,
},
{
name: "Team",
price: 49,
period: "/user/month",
description: "For growing teams",
features: [
"Everything in Pro",
"Team style sharing",
"Admin dashboard",
"SSO & SAML",
"Dedicated support",
],
cta: { label: "Contact Sales", href: "/contact" },
},
],
},
// === FAQ Section ===
faq: {
title: "Frequently asked questions",
subtitle: "Can't find what you're looking for? Reach out to our support team.",
items: [
{
question: "How does the AI learn my style?",
answer: "Our AI analyzes your writing patterns, vocabulary choices, and tone preferences. The more you write, the better it understands your unique voice. All learning happens locally and your data is never shared.",
},
{
question: "Is there a free trial?",
answer: "Yes! You can try Pro features free for 14 days, no credit card required. After that, you can continue on our free plan or upgrade to Pro.",
},
{
question: "Can I cancel anytime?",
answer: "Absolutely. No contracts, no cancellation fees. You can cancel your subscription at any time from your account settings.",
},
{
question: "Do you offer discounts for students?",
answer: "Yes, we offer 50% off for students and educators. Just verify your .edu email to get started.",
},
{
question: "Is my data private?",
answer: "100%. We use end-to-end encryption, never sell your data, and never train our models on your personal content. Your writing stays yours.",
},
],
},
// === Testimonials ===
testimonials: {
title: "Loved by writers everywhere",
items: [
{
quote: "This completely changed how I write. I'm 3x more productive now.",
author: "Sarah Chen",
role: "Content Lead",
company: "Stripe",
avatar: "/avatars/sarah.jpg",
},
{
quote: "Finally, an AI that actually sounds like me, not a robot.",
author: "Marcus Johnson",
role: "Technical Writer",
company: "Vercel",
avatar: "/avatars/marcus.jpg",
},
{
quote: "The best investment I've made for my writing workflow.",
author: "Emily Park",
role: "Freelance Writer",
company: "",
avatar: "/avatars/emily.jpg",
},
],
},
// === CTA Section ===
cta: {
title: "Ready to write better?",
subtitle: "Join 50,000+ writers who've upgraded their workflow.",
button: { label: "Start Free Trial", href: "/signup" },
note: "No credit card required · Cancel anytime",
},
// === Footer ===
footer: {
links: [
{
title: "Product",
items: [
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "Changelog", href: "/changelog" },
{ label: "Roadmap", href: "/roadmap" },
],
},
{
title: "Company",
items: [
{ label: "About", href: "/about" },
{ label: "Blog", href: "/blog" },
{ label: "Careers", href: "/careers" },
{ label: "Press", href: "/press" },
],
},
{
title: "Resources",
items: [
{ label: "Documentation", href: "/docs" },
{ label: "Help Center", href: "/help" },
{ label: "Community", href: "/community" },
{ label: "API", href: "/api" },
],
},
{
title: "Legal",
items: [
{ label: "Privacy", href: "/privacy" },
{ label: "Terms", href: "/terms" },
{ label: "Security", href: "/security" },
],
},
],
social: [
{ name: "Twitter", href: "https://twitter.com/acme", icon: "Twitter" },
{ name: "GitHub", href: "https://github.com/acme", icon: "Github" },
{ name: "Discord", href: "https://discord.gg/acme", icon: "MessageCircle" },
],
copyright: `© ${new Date().getFullYear()} Acme AI. All rights reserved.`,
},
}
// === Types ===
export type SiteConfig = typeof siteConfig