Skip to main content

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

Button Component

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

Input Component

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
/>
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

Header Component

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

import AdminLayout from '@/components/admin/AdminLayout';

// Main admin layout with sidebar
<AdminLayout>
  <AdminDashboard />
</AdminLayout>
Features:
  • Sidebar navigation
  • Mobile responsive
  • User dropdown
  • Breadcrumbs

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

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

Comment System

import CommentList from '@/components/comments/CommentList';

<CommentList
  postId={postId}
  comments={comments}
  onReply={handleReply}
  onLike={handleLike}
  onReport={handleReport}
/>

Astro Components & Layouts

Main Layout

src/layouts/Layout.astro
---
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:
src/pages/index.astro
---
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>

Performance Optimization

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

Build docs developers (and LLMs) love