# ATOMIC DESIGN STRUCTURE GUIDE ## Overview Project sử dụng **Atomic Design Pattern** để tổ chức UI components theo 5 cấp độ: 1. **Atoms** - Khối xây dựng cơ bản, không thể chia nhỏ hơn 2. **Molecules** - Nhóm atoms đơn giản hoạt động cùng nhau 3. **Organisms** - Khu vực UI phức tạp, riêng biệt 4. **Templates** - Bố cục cấp trang, cấu trúc nội dung 5. **Pages** - Các phiên bản cụ thể với dữ liệu thật --- ## 1) ATOMS (`components/atoms/`) **Mục đích:** Khối xây dựng cơ bản, tái sử dụng cao, không phụ thuộc logic phức tạp. Không có context/hooks logic phức tạp, chỉ nhận props từ parent. ### Cấu trúc thư mục ``` components/atoms/ ├── buttons/ │ ├── Button.tsx # Nút cơ bản (primary, secondary, danger) │ ├── IconButton.tsx # Nút chỉ có icon │ └── Button.types.ts # Props types ├── inputs/ │ ├── TextInput.tsx # Text input cơ bản │ ├── NumberInput.tsx # Number input với up/down │ ├── Checkbox.tsx # Checkbox │ └── Input.types.ts # Props types ├── badges/ │ ├── Badge.tsx # Badge cơ bản (color variants) │ ├── PriceBadge.tsx # Badge hiển thị giá │ └── Badge.types.ts # Props types ├── icons/ │ ├── StarIcon.tsx # Rating star icon │ ├── CartIcon.tsx # Shopping cart icon │ ├── SearchIcon.tsx # Search icon │ └── icons.types.ts # Props types ├── typography/ │ ├── Heading.tsx # h1-h6 headings │ ├── Text.tsx # Body text variants │ ├── Caption.tsx # Small caption text │ └── Typography.types.ts # Props types ├── dividers/ │ ├── Divider.tsx # Horizontal divider │ └── Divider.types.ts # Props types ├── loaders/ │ ├── Spinner.tsx # Loading spinner │ ├── Skeleton.tsx # Skeleton loader │ └── Loader.types.ts # Props types └── index.ts # Barrel export ``` ### Ví dụ Atoms **Button.tsx:** ```tsx import { ButtonHTMLAttributes } from "react"; import type { ButtonProps } from "./Button.types"; export default function Button({ variant = "primary", size = "md", disabled = false, children, className = "", ...props }: ButtonProps) { const baseStyles = "font-semibold rounded-lg transition-colors disabled:opacity-50"; const variants = { primary: "bg-[color:var(--color-primary)] text-white hover:bg-[color:var(--color-primary-dark)]", secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300", danger: "bg-red-500 text-white hover:bg-red-600", }; const sizes = { sm: "px-3 py-1 text-sm", md: "px-4 py-2 text-base", lg: "px-6 py-3 text-lg", }; return ( ); } ``` **Button.types.ts:** ```tsx import { ButtonHTMLAttributes } from "react"; export interface ButtonProps extends ButtonHTMLAttributes { variant?: "primary" | "secondary" | "danger"; size?: "sm" | "md" | "lg"; disabled?: boolean; children: React.ReactNode; className?: string; } ``` --- ## 2) MOLECULES (`components/molecules/`) **Mục đích:** Nhóm atoms tạo thành những UI unit nhỏ, tái sử dụng, có logic đơn giản. Có thể sử dụng `useState`, nhưng logic chủ yếu nằm ở parent component. ### Cấu trúc thư mục ``` components/molecules/ ├── form-groups/ │ ├── FormField.tsx # Input + label + error message │ ├── FormGroup.tsx # Label + input wrapper │ └── FormGroup.types.ts # Props types ├── cards/ │ ├── ProductCard.tsx # Card hiển thị sản phẩm (image + name + price + btn) │ ├── ShopCard.tsx # Card hiển thị quán │ ├── ReviewCard.tsx # Card hiển thị review │ └── Card.types.ts # Props types ├── ratings/ │ ├── RatingStars.tsx # Hiển thị 5 sao rating │ ├── RatingInput.tsx # Input 5 sao (interactive) │ └── Rating.types.ts # Props types ├── price-display/ │ ├── PriceTag.tsx # Hiển thị giá formatted │ ├── PriceRange.tsx # Hiển thị range giá │ └── Price.types.ts # Props types ├── search-bar/ │ ├── SearchInput.tsx # Search input với icon │ ├── SearchBar.tsx # Search bar wrapper │ └── Search.types.ts # Props types ├── breadcrumb/ │ ├── Breadcrumb.tsx # Breadcrumb navigation │ └── Breadcrumb.types.ts # Props types ├── tabs/ │ ├── TabGroup.tsx # Tabs wrapper │ ├── Tab.tsx # Individual tab │ └── Tabs.types.ts # Props types └── index.ts # Barrel export ``` ### Ví dụ Molecules **ProductCard.tsx:** ```tsx import Button from "@/components/atoms/buttons/Button"; import Text from "@/components/atoms/typography/Text"; import Image from "next/image"; import type { ProductCardProps } from "./Card.types"; export default function ProductCard({ product, onAddToCart, }: ProductCardProps) { return (
{product.name}
{product.name} {product.description}
${product.price.toFixed(2)}
); } ``` --- ## 3) ORGANISMS (`components/organisms/`) **Mục đích:** Khu vực UI phức tạp, độc lập, có logic riêng. Kết hợp multiple molecules/atoms, có thể sử dụng contexts (useAuth, useCart, etc.), state phức tạp. ### Cấu trúc thư mục ``` components/organisms/ ├── navigation/ │ ├── Navbar.tsx # Sidebar category filter (cũ CartProduct) │ ├── CategoryMenu.tsx # Category menu wrapper │ └── Navigation.types.ts # Props types ├── cart/ │ ├── CartFab.tsx # Floating action button giỏ hàng │ ├── CartSummary.tsx # Cart summary widget │ ├── CartList.tsx # Danh sách sản phẩm trong giỏ │ └── Cart.types.ts # Props types ├── product-grid/ │ ├── ProductGrid.tsx # Grid hiển thị danh sách sản phẩm │ ├── ProductFilters.tsx # Bộ lọc sản phẩm (category, price, rating) │ └── ProductGrid.types.ts # Props types ├── forms/ │ ├── LoginForm.tsx # Form đăng nhập (username + password + submit) │ ├── RegisterForm.tsx # Form đăng ký │ ├── CheckoutForm.tsx # Form thanh toán │ ├── ReviewForm.tsx # Form đánh giá (modal content) │ └── Forms.types.ts # Props types ├── modals/ │ ├── ReviewModal.tsx # Modal đánh giá (header + form + footer) │ ├── ConfirmModal.tsx # Modal xác nhận generic │ └── Modal.types.ts # Props types ├── shop-grid/ │ ├── ShopGrid.tsx # Grid hiển thị danh sách quán │ ├── ShopFilters.tsx # Bộ lọc quán (location, rating) │ └── ShopGrid.types.ts # Props types ├── hero-section/ │ ├── HeroSection.tsx # Banner hero cấp trang │ └── Hero.types.ts # Props types ├── featured-section/ │ ├── FeaturedProducts.tsx # Section sản phẩm nổi bật │ ├── FeaturedShops.tsx # Section quán nổi bật │ └── Featured.types.ts # Props types └── index.ts # Barrel export ``` ### Ví dụ Organisms **ProductGrid.tsx:** ```tsx "use client"; import ProductCard from "@/components/molecules/cards/ProductCard"; import { useCart } from "@/lib/cart-context"; import { MOCK_PRODUCTS } from "@/lib/constants"; import { useMenu } from "@/lib/menu-context"; import type { ProductGridProps } from "./ProductGrid.types"; export default function ProductGrid({ searchQuery = "" }: ProductGridProps) { const { activeCategory } = useMenu(); const { addToCart } = useCart(); const filtered = MOCK_PRODUCTS.filter((product) => { const matchCategory = activeCategory === "all" || product.category === activeCategory; const matchSearch = product.name.toLowerCase().includes(searchQuery.toLowerCase()) || product.description.toLowerCase().includes(searchQuery.toLowerCase()); return matchCategory && matchSearch; }); return (
{filtered.map((product) => ( ))}
); } ``` --- ## 4) TEMPLATES (`components/templates/`) **Mục đích:** Bố cục cấp trang, cấu trúc nội dung, không có data cụ thể. Chứa layout và structure của page, nhưng data được truyền từ page component. ### Cấu trúc thư mục ``` components/templates/ ├── main-layout/ │ ├── MainLayout.tsx # Layout chính (header + sidebar + content + footer) │ ├── MainLayout.types.ts # Props types │ └── styles.ts # Responsive grid layout logic ├── feed-layout/ │ ├── FeedLayout.tsx # Layout feed (khám phá quán) │ └── FeedLayout.types.ts # Props types ├── manager-layout/ │ ├── ManagerLayout.tsx # Layout manager dashboard │ └── ManagerLayout.types.ts # Props types ├── checkout-layout/ │ ├── CheckoutLayout.tsx # Layout thanh toán (steps, cart, form) │ └── CheckoutLayout.types.ts # Props types ├── auth-layout/ │ ├── AuthLayout.tsx # Layout auth (login/register) │ └── AuthLayout.types.ts # Props types └── index.ts # Barrel export ``` ### Ví dụ Templates **MainLayout.tsx:** ```tsx import Navbar from "@/components/organisms/navigation/Navbar"; import Footer from "@/layouts/footer"; import Header from "@/layouts/header"; import type { MainLayoutProps } from "./MainLayout.types"; export default function MainLayout({ children }: MainLayoutProps) { return (
{/* Sidebar - ẩn trên mobile */} {/* Main content */}
{children}
); } ``` --- ## 5) PAGES (`app/*/page.tsx`) **Mục đích:** Các phiên bản cụ thể với dữ liệu thật, logic cấp trang. Server/client components sử dụng templates, organisms, nhận data từ API/context. ### Ví dụ Pages **app/(main)/page.tsx:** ```tsx "use client"; import FeaturedSection from "@/components/organisms/featured-section/FeaturedSection"; import ProductGrid from "@/components/organisms/product-grid/ProductGrid"; import MainLayout from "@/components/templates/main-layout/MainLayout"; import { useState } from "react"; export default function MainPage() { const [searchQuery, setSearchQuery] = useState(""); return (
); } ``` --- ## 6) File Hierarchy Summary ``` components/ ├── atoms/ │ ├── buttons/ │ ├── inputs/ │ ├── badges/ │ ├── icons/ │ ├── typography/ │ ├── dividers/ │ ├── loaders/ │ └── index.ts ├── molecules/ │ ├── form-groups/ │ ├── cards/ │ ├── ratings/ │ ├── price-display/ │ ├── search-bar/ │ ├── breadcrumb/ │ ├── tabs/ │ └── index.ts ├── organisms/ │ ├── navigation/ │ ├── cart/ │ ├── product-grid/ │ ├── forms/ │ ├── modals/ │ ├── shop-grid/ │ ├── hero-section/ │ ├── featured-section/ │ └── index.ts ├── templates/ │ ├── main-layout/ │ ├── feed-layout/ │ ├── manager-layout/ │ ├── checkout-layout/ │ ├── auth-layout/ │ └── index.ts └── ATOMIC_DESIGN.md (this file) ``` --- ## 7) Migration Guide (Old → New) ### Old Structure → New Structure Mapping | Old File | New Location | Type | | ----------------- | ---------------------------------- | -------- | | `CartProduct.tsx` | `molecules/cards/ProductCard.tsx` | Molecule | | `Navbar.tsx` | `organisms/navigation/Navbar.tsx` | Organism | | `CartFab.tsx` | `organisms/cart/CartFab.tsx` | Organism | | `ReviewModal.tsx` | `organisms/modals/ReviewModal.tsx` | Organism | ### Migration Steps 1. Create new directory structure under `components/` 2. Move existing components to appropriate levels (atoms → molecules → organisms) 3. Extract shared styles/logic into atoms 4. Update imports in `app/` pages 5. Test responsiveness at each breakpoint 6. Update `COMPONENTS.md` with new structure --- ## 8) Best Practices ### Atoms Development - ✅ Reusable across entire project - ✅ No business logic - ✅ No context/hooks (useAuth, useCart) - ✅ Pure props-based - ✅ Full TypeScript typing - ❌ No "use client" needed (unless interactive, e.g., Button) ### Molecules Development - ✅ Combines multiple atoms - ✅ Simple state (open/close, hover state) - ✅ No complex business logic - ✅ Can use useState for UI state - ✅ Reusable in multiple contexts - ❌ No global state (useAuth, useCart) ### Organisms Development - ✅ Complex UI sections - ✅ Can use contexts (useAuth, useCart, useMenu) - ✅ Business logic - ✅ Always "use client" - ✅ Filter, sort, complex interactions - ❌ Not reusable across different page types ### Templates Development - ✅ Page layout structure - ✅ Composition of organisms + layout - ✅ No data fetching/business logic - ✅ Children prop pattern - ✅ Props for customization - ❌ No hardcoded data ### Pages Development - ✅ Specific page implementations - ✅ Route-specific logic - ✅ Data integration - ✅ Context usage at page level - ✅ State management orchestration - ❌ No UI component definitions (use organisms) --- ## 9) Import Patterns ### Atoms ```tsx import Button from "@/components/atoms/buttons/Button"; import Text from "@/components/atoms/typography/Text"; ``` ### Molecules ```tsx import ProductCard from "@/components/molecules/cards/ProductCard"; import FormField from "@/components/molecules/form-groups/FormField"; ``` ### Organisms ```tsx import LoginForm from "@/components/organisms/forms/LoginForm"; import ProductGrid from "@/components/organisms/product-grid/ProductGrid"; ``` ### Templates ```tsx import MainLayout from "@/components/templates/main-layout/MainLayout"; ``` ### Barrel Exports ```tsx // Usage import { Button, Text } from "@/components/atoms"; // components/atoms/index.ts export { default as Button } from "./buttons/Button"; export { default as Text } from "./typography/Text"; export * from "./buttons/Button.types"; ``` --- ## 10) Common Patterns ### Creating a New Atom ```tsx // atoms/buttons/NewButton.tsx export default function NewButton({ variant, ...props }: Props) { return ``` --- ## 14) Version Control & Documentation ### File Format ``` components/ ├── atoms/ │ ├── buttons/ │ │ ├── Button.tsx │ │ ├── Button.types.ts │ │ └── Button.md # Component documentation │ └── ... ├── molecules/ │ ├── cards/ │ │ ├── ProductCard.tsx │ │ ├── Card.types.ts │ │ └── ProductCard.md │ └── ... └── ... ``` ### Documentation Template ```markdown # ProductCard ## Purpose Display individual product with image, name, price, and action button. ## Props - `product: Product` - Product data - `onAddToCart: (product: Product) => void` - Add to cart handler ## Usage \`\`\`tsx \`\`\` ## Variants - Image with loading state - With discount badge - With rating stars ## Responsive - Mobile: Single column, full width - Desktop: Grid layout ``` --- Cấu trúc này cung cấp: ✅ **Scalability**: Dễ thêm components mới ✅ **Reusability**: Tối đa tái sử dụng ✅ **Maintainability**: Code dễ hiểu, tìm kiếm ✅ **Testability**: Mỗi level có logic riêng ✅ **Performance**: Smart code-splitting