xiaohongshu
xiaohongshu
component-organization
Maintain consistent file structure - components/ui for base shadcn, components/shared for composed components, pages for routes, always use barrel exports
Full skill instructions
This guide establishes the file structure and naming conventions for maintaining a consistent, scalable React TypeScript codebase.
src/
├── assets/ # Static assets (images, icons, fonts)
│ ├── icons/
│ └── images/
├── components/ # Reusable components
│ ├── ui/ # Base shadcn components (CLI-generated)
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── badge.tsx
│ │ └── index.ts # Barrel export
│ ├── shared/ # Composed app-specific components
│ │ ├── UserProfileCard.tsx
│ │ ├── DataTable.tsx
│ │ └── index.ts # Barrel export
│ └── index.ts # Root barrel export
├── pages/ # Top-level route components
│ ├── Home.tsx
│ ├── About.tsx
│ ├── NotFound.tsx
│ └── index.ts # Barrel export
├── layouts/ # Layout wrappers
│ ├── MainLayout.tsx
│ ├── DashboardLayout.tsx
│ └── index.ts # Barrel export
├── features/ # Feature-based organization (optional)
│ ├── authentication/
│ │ ├── components/
│ │ ├── hooks/
│ │ └── index.ts
│ └── dashboard/
│ ├── components/
│ ├── hooks/
│ └── index.ts
├── hooks/ # Custom React hooks
│ ├── useLocalStorage.ts
│ └── index.ts # Barrel export
├── lib/ # Utilities and helpers
│ └── utils.ts # cn() helper for Tailwind
├── services/ # API and external services
│ ├── api.service.ts
│ └── index.ts # Barrel export
├── constants/ # App-wide constants
│ └── index.ts # APP_NAME, ROUTES, etc.
├── types/ # TypeScript type definitions
│ ├── api.types.ts
│ ├── common.types.ts
│ └── index.ts # Barrel export
└── utils/ # Pure utility functions
└── index.ts
components/ui/Purpose: Base shadcn/ui components generated via CLI
npx shadcn@latest add [component]Example:
// components/ui/button.tsx (generated by shadcn CLI)
import * as React from "react"
import { cn } from "@/lib/utils"
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
components/shared/Purpose: Composed, app-specific components built from base UI components
ui/ componentsExample:
// components/shared/UserProfileCard.tsx
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
export interface UserProfileCardProps {
name: string;
role: string;
avatar: string;
}
export function UserProfileCard({ name, role, avatar }: UserProfileCardProps) {
return (
<Card>
<CardHeader>
<img src={avatar} alt={name} className="h-16 w-16 rounded-full" />
<CardTitle>{name}</CardTitle>
<Badge>{role}</Badge>
</CardHeader>
<CardContent>
{/* Additional user details */}
</CardContent>
</Card>
);
}
pages/Purpose: Top-level route components that render at specific URLs
Example:
// pages/Home.tsx
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { APP_NAME } from '@/constants';
export function Home() {
const features = [
{
title: 'Vite',
badge: 'Fast',
description: 'Lightning-fast build tool with HMR.',
gradient: 'from-violet-500 to-purple-500',
},
// ... more features
];
return (
<div className="space-y-32">
{/* Hero Section */}
<div className="relative overflow-hidden">
<h1 className="text-6xl font-extrabold">{APP_NAME}</h1>
<p className="text-xl text-gray-600">
A modern React TypeScript starter
</p>
</div>
{/* Features Grid */}
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{features.map((feature) => (
<Card key={feature.title}>
<CardHeader>
<CardTitle>{feature.title}</CardTitle>
<Badge>{feature.badge}</Badge>
<CardDescription>{feature.description}</CardDescription>
</CardHeader>
</Card>
))}
</div>
</div>
);
}
layouts/Purpose: Wrapper components that provide consistent structure across pages
<Outlet /> from react-router for nested routingExample:
// layouts/MainLayout.tsx
import { Link, Outlet, useLocation } from 'react-router-dom';
export function MainLayout() {
const location = useLocation();
const isActive = (path: string) => location.pathname === path;
return (
<div className="min-h-screen bg-white">
{/* Navigation Header */}
<header className="sticky top-0 z-50 border-b bg-white/95">
<nav className="mx-auto max-w-7xl px-8 py-4">
<div className="flex items-center gap-8">
<Link
to="/"
className={`px-4 py-2 font-medium ${
isActive('/') ? 'text-blue-600' : 'text-gray-600'
}`}
>
Home
</Link>
<Link
to="/about"
className={`px-4 py-2 font-medium ${
isActive('/about') ? 'text-blue-600' : 'text-gray-600'
}`}
>
About
</Link>
</div>
</nav>
</header>
{/* Main Content */}
<main className="mx-auto max-w-7xl px-8 py-16">
<Outlet />
</main>
</div>
);
}
lib/Purpose: Core utilities and helper functions
cn() helper for Tailwind class mergingutils/ instead)Example:
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
constants/Purpose: Application-wide constants and configuration
as const for type safetyExample:
// constants/index.ts
export const APP_NAME = 'Vite React TypeScript Boilerplate';
export const API_BASE_URL =
import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api';
export const ROUTES = {
HOME: '/',
ABOUT: '/about',
NOT_FOUND: '*',
} as const;
export const STORAGE_KEYS = {
AUTH_TOKEN: 'auth_token',
USER_PREFERENCES: 'user_preferences',
} as const;
Always create index.ts files to enable clean imports and maintain a clear public API.
// components/ui/index.ts
export { Button } from './button';
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
} from './card';
export { Badge } from './badge';
export { Separator } from './separator';
// Only use when all exports from a module should be public
export * from './button';
export * from './card';
// components/index.ts - Exposes nested directories
export { Button } from './ui/button';
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
} from './ui/card';
Benefits:
import { Button, Card } from '@/components'Format: PascalCase
Button.tsx, UserProfileCard.tsx, MainLayout.tsxexport function Button(), export function UserProfileCard()Format: camelCase or kebab-case
utils.ts, api.service.ts, useLocalStorage.tsexport function cn(), export function useLocalStorage()Format: kebab-case
components/ui, components/shared, pages, layoutsFormat: SCREAMING_SNAKE_CASE
APP_NAME, API_BASE_URL, STORAGE_KEYSFormat: PascalCase with descriptive suffix
UserProfileCardProps, ApiResponse, AuthState┌─────────────────────────────────────┐
│ Need to create a new component? │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Is it a shadcn/ui base component? │
└──────────────┬──────────────────────┘
│
┌─────┴─────┐
│ │
YES NO
│ │
▼ ▼
┌─────────┐ ┌──────────────────────────────────┐
│ Use CLI │ │ Is it used in 2+ different │
│ to add │ │ features/pages? │
│ to ui/ │ └──────────────┬───────────────────┘
└─────────┘ │
┌─────┴─────┐
│ │
YES NO
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────────┐
│ Does it compose │ │ Is it a full page │
│ multiple ui/ │ │ route? │
│ components? │ └──────────┬──────────┘
└────────┬─────────┘ │
│ ┌────────┴────────┐
┌─────┴─────┐ │ │
│ │ YES NO
YES NO │ │
│ │ ▼ ▼
▼ ▼ ┌────────┐ ┌──────────────┐
┌──────────┐ ┌────────┐│ pages/ │ │ Is it part │
│ shared/ │ │ hooks/ ││ │ │ of a cohesive│
│ │ │ or │└────────┘ │ feature? │
└──────────┘ │ utils/ │ └──────┬───────┘
└────────┘ │
┌────────┴────────┐
│ │
YES NO
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ features/ │ │ Colocate with│
│ [feature]/ │ │ parent │
│ components/ │ │ component │
└──────────────┘ └──────────────┘
If you're copying the same JSX structure more than twice, extract it into a component.
Before:
// Multiple pages with duplicated card structure
export function Dashboard() {
return (
<Card>
<CardHeader>
<CardTitle>Stats</CardTitle>
</CardHeader>
<CardContent>{/* ... */}</CardContent>
</Card>
);
}
export function Profile() {
return (
<Card>
<CardHeader>
<CardTitle>User Info</CardTitle>
</CardHeader>
<CardContent>{/* ... */}</CardContent>
</Card>
);
}
After:
// components/shared/StatsCard.tsx
export function StatsCard({ title, children }) {
return (
<Card>
<CardHeader>
<CardTitle>{title}</CardTitle>
</CardHeader>
<CardContent>{children}</CardContent>
</Card>
);
}
If a component or section exceeds 50 lines, consider extracting it.
Before:
export function Dashboard() {
return (
<div>
{/* 80 lines of user profile UI */}
<div className="user-profile">
{/* Complex profile rendering */}
</div>
{/* 60 lines of statistics UI */}
<div className="statistics">
{/* Complex stats rendering */}
</div>
</div>
);
}
After:
export function Dashboard() {
return (
<div>
<UserProfile />
<Statistics />
</div>
);
}
When combining 3+ base UI components, create a composed component.
// components/shared/UserCard.tsx - Composes Card, Badge, Button
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
export function UserCard({ user }) {
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>{user.name}</CardTitle>
<Badge>{user.role}</Badge>
</div>
</CardHeader>
<CardContent>
<p>{user.email}</p>
<Button variant="outline">View Profile</Button>
</CardContent>
</Card>
);
}
When adding business logic, API calls, or state management, extract to a component.
// components/shared/ProductList.tsx - Contains domain logic
import { useEffect, useState } from 'react';
import { fetchProducts } from '@/services/api.service';
import { Card } from '@/components/ui/card';
export function ProductList() {
const [products, setProducts] = useState([]);
useEffect(() => {
fetchProducts().then(setProducts);
}, []);
return (
<div className="grid gap-4">
{products.map(product => (
<Card key={product.id}>
{/* Product display */}
</Card>
))}
</div>
);
}
// src/components/ui/index.ts
export { Button } from './button';
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
} from './card';
export { Badge } from './badge';
export { Separator } from './separator';
// src/pages/Home.tsx
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { APP_NAME } from '@/constants';
export function Home() {
// Page orchestrates UI components
return (
<div className="space-y-32">
<h1>{APP_NAME}</h1>
{/* Feature showcase using composed components */}
</div>
);
}
// src/layouts/MainLayout.tsx
import { Link, Outlet, useLocation } from 'react-router-dom';
export function MainLayout() {
const location = useLocation();
return (
<div className="min-h-screen">
<header className="sticky top-0">
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
</header>
<main>
<Outlet /> {/* Pages render here */}
</main>
</div>
);
}
// src/constants/index.ts
export const APP_NAME = 'Vite React TypeScript Boilerplate';
export const ROUTES = {
HOME: '/',
ABOUT: '/about',
NOT_FOUND: '*',
} as const;
// Usage in pages
import { ROUTES } from '@/constants';
<Link to={ROUTES.HOME}>Home</Link>
index.ts for new directory?components/ui/?components/shared/?pages/ directory?layouts/ directory?@/ path alias for imports?DON'T modify shadcn UI components directly:
// ❌ Bad: Editing ui/button.tsx manually
// If you need customization, create a wrapper in shared/
DON'T skip barrel exports:
// ❌ Bad: Direct imports without barrel
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
// ✅ Good: Use barrel exports
import { Button, Card } from '@/components/ui';
DON'T create one-off components in shared/:
// ❌ Bad: Single-use component in shared/
// components/shared/HomepageHeroSection.tsx (only used once)
// ✅ Good: Keep in the page or feature
// pages/Home.tsx (inline) or features/homepage/components/
DON'T mix concerns in constants:
// ❌ Bad: Mixing types and runtime values
export const ENDPOINTS = {
users: '/api/users',
auth: '/api/auth',
};
export type User = { id: string; name: string };
// ✅ Good: Separate constants and types
// constants/index.ts - runtime values
// types/index.ts - type definitions
Remember: Good organization makes scaling easy. When in doubt, follow the principle: "Start simple, extract when you repeat."
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience