Component Overview
The Blog Marketing Platform uses a hybrid component architecture combining Astro components for static content and React components for interactive UI. All components are organized by feature and responsibility.
Components are located in /src/components/ with clear separation between static (Astro) and interactive (React) components.
Component Categories
UI Components Reusable design system (Button, Input, Modal, Card)
Layout Components Header, Footer, navigation, page layouts
Feature Components Domain-specific (Admin, Blog, Profile, Comments)
Astro Components Static layouts and page structures
Directory Structure
src/components/
├── ui/ # Reusable UI components
│ ├── Button.tsx
│ ├── Input.tsx
│ ├── Modal.tsx
│ ├── Card.tsx
│ ├── Checkbox.tsx
│ └── ConfirmDialog.tsx
├── layout/ # Layout components
│ ├── Header.tsx
│ └── Footer.tsx
├── admin/ # Admin dashboard
│ ├── AdminDashboard.tsx
│ ├── AdminLayout.tsx
│ ├── AdminHeader.tsx
│ ├── AdminPostsPage.tsx
│ ├── AdminUsersPage.tsx
│ └── ...
├── auth/ # Authentication UI
│ ├── LoginForm.tsx
│ └── RegisterForm.tsx
├── blog/ # Blog components
│ ├── PostCard.tsx
│ ├── PostList.tsx
│ └── PostDetail.tsx
├── comments/ # Comment system
│ ├── CommentList.tsx
│ ├── CommentForm.tsx
│ └── CommentItem.tsx
├── dashboard/ # Dashboard widgets
│ └── StatCard.tsx
├── editor/ # Content editors
│ └── mdx/
│ ├── OptimizedMdxEditor.tsx
│ └── MdxPreviewRenderer.tsx
├── home/ # Homepage sections
│ ├── HeroSection.tsx
│ ├── ServicesSection.tsx
│ └── TestimonialsSection.tsx
├── profile/ # User profiles
│ ├── UserProfile.tsx
│ ├── EditProfile.tsx
│ ├── ProfileHeader.tsx
│ └── forms/
│ ├── GeneralProfileForm.tsx
│ ├── SecurityProfileForm.tsx
│ └── ...
├── tools/ # Marketing tools
│ └── ROICalculator.tsx
└── animations/ # Animation components
└── FadeIn.tsx
UI Component Library
A versatile button component with multiple variants and sizes.
import Button from '@/components/ui/Button' ;
// Primary button
< Button variant = "primary" size = "md" onClick = { handleClick } >
Click Me
</ Button >
// Link button
< Button variant = "outline" href = "/dashboard" >
Go to Dashboard
</ Button >
// Loading state
< Button variant = "primary" loading = { isLoading } >
Submit
</ Button >
Features:
5 style variants
3 size options
Loading state with spinner
Framer Motion animations
Works as button or link
import Input from '@/components/ui/Input' ;
< Input
label = "Email"
type = "email"
placeholder = "[email protected] "
value = { email }
onChange = { ( e ) => setEmail ( e . target . value ) }
error = { errors . email }
required
/>
Modal Component
import Modal from '@/components/ui/Modal' ;
< Modal
isOpen = { isOpen }
onClose = { handleClose }
title = "Confirm Action"
size = "md"
>
< p > Are you sure you want to continue? </ p >
< div className = "flex gap-2 mt-4" >
< Button onClick = { handleConfirm } > Confirm </ Button >
< Button variant = "outline" onClick = { handleClose } > Cancel </ Button >
</ div >
</ Modal >
Sizes: sm, md, lg, xl
Card Component
import Card from '@/components/ui/Card' ;
< Card
title = "Statistics"
description = "View your performance metrics"
footer = {
< Button variant = "outline" size = "sm" > View Details </ Button >
}
>
< div className = "space-y-4" >
{ /* Card content */ }
</ div >
</ Card >
ConfirmDialog Component
import ConfirmDialog from '@/components/ui/ConfirmDialog' ;
< ConfirmDialog
isOpen = { showConfirm }
onConfirm = { handleDelete }
onCancel = { () => setShowConfirm ( false ) }
title = "Delete Post"
message = "This action cannot be undone. Are you sure?"
confirmText = "Delete"
cancelText = "Cancel"
variant = "danger"
/>
Layout Components
The main navigation header with responsive design.
src/components/layout/Header.tsx
import Header from '@/components/layout/Header' ;
// Features:
// - Desktop & mobile navigation
// - Theme switcher (light/dark)
// - Search functionality
// - Sticky positioning
// - Animated mobile menu
< Header client : load />
Key Features:
Responsive navigation
Dark mode toggle
Search integration
Sticky header with backdrop blur
Framer Motion animations
src/components/layout/Footer.tsx
import Footer from '@/components/layout/Footer' ;
// Features:
// - Multi-column layout
// - Social media links
// - Newsletter signup
// - Copyright info
< Footer />
Feature Components
Admin Dashboard
AdminLayout
AdminDashboard
AdminPostsPage
import AdminLayout from '@/components/admin/AdminLayout' ;
// Main admin layout with sidebar
< AdminLayout >
< AdminDashboard />
</ AdminLayout >
Features:
Sidebar navigation
Mobile responsive
User dropdown
Breadcrumbs
import AdminDashboard from '@/components/admin/AdminDashboard' ;
// Dashboard with stats and charts
< AdminDashboard />
Includes:
Overview statistics
Charts with Recharts
Recent activity feed
Quick actions
import AdminPostsPage from '@/components/admin/AdminPostsPage' ;
// Complete posts management
< AdminPostsPage />
Features:
Posts table with filters
Bulk actions
Status updates
Search and pagination
Blog Components
import PostCard from '@/components/blog/PostCard' ;
< PostCard
post = { {
id: '1' ,
title: 'Getting Started with SEO' ,
excerpt: 'Learn the basics...' ,
image: '/images/post.jpg' ,
author: { name: 'John Doe' , avatar: '/avatar.jpg' },
publishedAt: '2024-03-01' ,
readTime: '5 min' ,
category: 'SEO'
} }
/>
Profile Components
Profile Component Structure
import UserProfile from '@/components/profile/UserProfile' ;
import EditProfile from '@/components/profile/EditProfile' ;
import ProfileHeader from '@/components/profile/ProfileHeader' ;
// Profile view
< UserProfile userId = { 123 } />
// Edit mode with forms
< EditProfile userId = { 123 } />
// Standalone header
< ProfileHeader
user = { user }
onEditAvatar = { handleAvatarEdit }
onEditCover = { handleCoverEdit }
/>
Profile Forms:
GeneralProfileForm - Name, bio, location
SecurityProfileForm - Password, 2FA
PrivacySettingsForm - Privacy controls
PreferencesProfileForm - Notifications, theme
SocialLinksForm - Social media links
Editor Components
Advanced MDX editor for creating rich content.
src/components/editor/mdx/OptimizedMdxEditor.tsx
import OptimizedMdxEditor from '@/components/editor/mdx/OptimizedMdxEditor' ;
< OptimizedMdxEditor
initialContent = { post ?. content || '' }
onChange = { handleContentChange }
placeholder = "Start writing..."
/>
Features:
Live preview
Markdown syntax support
Code highlighting
Image upload
Keyboard shortcuts
import CommentList from '@/components/comments/CommentList' ;
< CommentList
postId = { postId }
comments = { comments }
onReply = { handleReply }
onLike = { handleLike }
onReport = { handleReport }
/>
Astro Components & Layouts
Main Layout
---
import '../styles/tailwind.css' ;
const {
title ,
description ,
image ,
noindex
} = Astro . props ;
---
< ! DOCTYPE html >
< html lang = "es" >
< head >
< meta charset = "UTF-8" />
< title > { title } </ title >
< meta name = "description" content = { description } />
<!-- SEO, OG tags, etc. -->
</ head >
< body >
< slot />
</ body >
</ html >
Usage in pages:
---
import Layout from '../layouts/Layout.astro' ;
import Header from '../components/layout/Header.tsx' ;
import HeroSection from '../components/home/HeroSection.tsx' ;
---
< Layout title = "Home - Marketing Pro" >
< Header client:load />
< main >
< HeroSection client:load />
</ main >
</ Layout >
Component Patterns
1. Client Directives
Astro components are static by default. Use directives for interactivity:
<!-- Load immediately on page load -->
< Header client:load />
<!-- Load when browser is idle -->
< Newsletter client:idle />
<!-- Load when component is visible -->
< LazyChart client:visible />
<!-- Only render on client (skip SSR) -->
< ReactOnlyWidget client:only = "react" />
2. Compound Components
import Card from '@/components/ui/Card' ;
< Card >
< Card.Header >
< Card.Title > Statistics </ Card.Title >
< Card.Description > Monthly overview </ Card.Description >
</ Card.Header >
< Card.Body >
{ /* Content */ }
</ Card.Body >
< Card.Footer >
< Button > View More </ Button >
</ Card.Footer >
</ Card >
3. Render Props
< DataTable
data = { users }
columns = { columns }
renderRow = { ( user ) => (
< tr key = { user . id } >
< td > { user . name } </ td >
< td > { user . email } </ td >
</ tr >
) }
/>
4. Component Composition
// Small, focused components
const Avatar = ({ src , alt }) => (
< img className = "rounded-full" src = { src } alt = { alt } />
);
const UserInfo = ({ name , email }) => (
< div >
< p className = "font-bold" > { name } </ p >
< p className = "text-sm text-gray-600" > { email } </ p >
</ div >
);
// Compose into larger component
const UserCard = ({ user }) => (
< Card >
< div className = "flex items-center gap-4" >
< Avatar src = { user . avatar } alt = { user . name } />
< UserInfo name = { user . name } email = { user . email } />
</ div >
</ Card >
);
Styling Approach
Tailwind CSS
All components use Tailwind utility classes:
< button className = "
px-4 py-2
bg-primary-500 hover:bg-primary-600
text-white
rounded-lg
transition-colors duration-200
focus:outline-none focus:ring-2 focus:ring-primary-500
" >
Click Me
</ button >
Dark Mode
Dark mode support using Tailwind’s dark variant:
< div className = "
bg-white dark:bg-gray-900
text-gray-900 dark:text-gray-100
" >
Content
</ div >
Responsive Design
< div className = "
grid
grid-cols-1 /* Mobile: 1 column */
md:grid-cols-2 /* Tablet: 2 columns */
lg:grid-cols-3 /* Desktop: 3 columns */
gap-4
" >
{ items . map ( item => < Item key = { item . id } { ... item } /> ) }
</ div >
Animation with Framer Motion
Many components use Framer Motion for smooth animations:
import { motion , AnimatePresence } from 'framer-motion' ;
< AnimatePresence >
{ isOpen && (
< motion.div
initial = { { opacity: 0 , y: - 20 } }
animate = { { opacity: 1 , y: 0 } }
exit = { { opacity: 0 , y: - 20 } }
transition = { { duration: 0.2 } }
>
< Modal > Content </ Modal >
</ motion.div >
) }
</ AnimatePresence >
Code Splitting Components are automatically code-split by Astro and Vite
Lazy Loading Use client:visible for below-fold components
Memoization React.memo() for expensive components
Dynamic Imports Lazy load heavy components on demand
// Lazy load heavy component
const HeavyChart = lazy (() => import ( './HeavyChart' ));
< Suspense fallback = { < Spinner /> } >
< HeavyChart data = { data } />
</ Suspense >
Testing Components
Component testing setup is recommended using React Testing Library or Vitest.
import { render , screen , fireEvent } from '@testing-library/react' ;
import Button from '@/components/ui/Button' ;
test ( 'button triggers onClick' , () => {
const handleClick = jest . fn ();
render ( < Button onClick = { handleClick } > Click </ Button > );
fireEvent . click ( screen . getByText ( 'Click' ));
expect ( handleClick ). toHaveBeenCalledTimes ( 1 );
});
Best Practices
Keep components small and focused. If a component exceeds 200 lines, consider breaking it into smaller pieces.
Use TypeScript interfaces for all props: interface ButtonProps {
variant : 'primary' | 'secondary' ;
size ?: 'sm' | 'md' | 'lg' ;
onClick ?: () => void ;
children : React . ReactNode ;
}
const Button : React . FC < ButtonProps > = ({ variant , size = 'md' , onClick , children }) => {
// ...
};
Use destructuring with defaults: const Card = ({
variant = 'default' ,
padding = 'md' ,
children
}) => {
// ...
};
Name event handlers with handle prefix: const handleClick = () => { /* ... */ };
const handleSubmit = ( e ) => { /* ... */ };
Next Steps
Architecture Understanding the project structure
Services Learn about the API service layer
State Management Zustand stores and state
Styling Guide Tailwind CSS and design system