Content Calendar

Last updated on 2026-03-26

The content calendar provides a visual month-view calendar for scheduling, rescheduling, and managing social media posts across all platforms. It uses @hello-pangea/dnd for drag-and-drop post rescheduling and includes a day detail sheet for managing posts on a specific date. The calendar page is in the (dashboard) route group.

Calendar Overview

Route: /calendar

The content calendar displays scheduled, published, and draft posts on a month grid. Each post appears as a color-coded pill on its scheduled date.

  • Month navigation -- previous/next month buttons with the current month and year displayed as a heading
  • Calendar grid -- CalendarGrid component rendering a 7-column grid (Mon-Sun) with CalendarDayCell components for each day
  • Post pills -- CalendarPostPill components within each day cell, color-coded by platform (Instagram pink, Twitter blue, Facebook blue, LinkedIn blue, TikTok teal, YouTube red) with a truncated caption and media type icon
  • Drag-and-drop rescheduling -- drag a post pill from one day to another to reschedule it; uses @hello-pangea/dnd DragDropContext, Droppable (each day cell), and Draggable (each post pill)
  • Day detail sheet -- click a day cell to open the DayDetailSheet (a Sheet component sliding in from the right) showing all posts for that day with full details, status, and quick actions
  • Today indicator -- the current date cell is highlighted with a teal ring
  • Post count overflow -- days with more than 3 posts show a "+N more" indicator that opens the day detail sheet
import { CalendarGrid } from "@/components/calendar/calendar-grid"
import { CalendarDayCell } from "@/components/calendar/calendar-day-cell"
import { CalendarPostPill } from "@/components/calendar/calendar-post-pill"
import { DayDetailSheet } from "@/components/calendar/day-detail-sheet"

Calendar Layout

┌───────────────────────────────────────────┐
│ < March 2026 >                   [+ Post] │
├─────┬─────┬─────┬─────┬─────┬─────┬─────┤
│ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │ Sun │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│     │     │  1  │  2  │  3  │  4  │  5  │
│     │     │ [IG]│     │ [TW]│     │     │
│     │     │ [FB]│     │     │     │     │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│  6  │  7  │  8  │  9  │ 10  │ 11  │ 12  │
│ [LI]│     │ [IG]│ [TT]│     │ [YT]│     │
│     │     │ [TW]│     │     │     │     │
│     │     │ +1  │     │     │     │     │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│ ... │     │     │     │     │     │     │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘

Post Pill Colors

Each CalendarPostPill uses the platform brand color as its background:

Platform Pill Color Abbreviation
Instagram #E1306C (pink) IG
Twitter/X #1DA1F2 (blue) TW
Facebook #1877F2 (blue) FB
LinkedIn #0A66C2 (blue) LI
TikTok #00F2EA (teal) TT
YouTube #FF0000 (red) YT

Drag-and-Drop

The calendar uses @hello-pangea/dnd (a maintained fork of react-beautiful-dnd) for drag-and-drop post rescheduling.

How It Works

  1. Each CalendarDayCell is a Droppable zone identified by its date string
  2. Each CalendarPostPill is a Draggable item identified by its post ID
  3. When a pill is dropped on a different day cell, the post's scheduledAt date is updated to the target date while preserving the original time
  4. A toast notification confirms the reschedule with the old and new dates

Keyboard Accessibility

The drag-and-drop supports full keyboard interaction:

  • Space -- lift and drop a post pill
  • Arrow keys -- move a lifted pill between day cells
  • Escape -- cancel a drag operation and return the pill to its original date

Data Flow

// CalendarPost type used for calendar display
interface CalendarPost {
  id: string
  postId: string
  caption: string
  platform: SocialPlatform
  time: string
  date: string
  mediaType: PostType
  status: PostStatus
}

Day Detail Sheet

The DayDetailSheet is a Sheet component that slides in from the right when a day cell is clicked. It provides a detailed view of all posts scheduled for that day.

  • Date heading -- formatted date (e.g., "Wednesday, March 11, 2026")
  • Post list -- each post shows platform badge, time, caption, media type, status badge, and engagement metrics (for published posts)
  • Quick actions -- edit, reschedule, duplicate, and delete buttons for each post
  • Add post button -- link to the composer with the selected date pre-filled
  • Empty state -- message shown when no posts are scheduled for the day, with a prompt to create one

Day Detail Layout

┌─────────────────────────────┐
│ Wednesday, March 11, 2026   │
├─────────────────────────────┤
│ 9:00 AM  [IG] Product shot  │
│ Status: Scheduled           │
│ [Edit] [Reschedule] [...]   │
├─────────────────────────────┤
│ 2:00 PM  [TW] Thread about  │
│ Status: Draft               │
│ [Edit] [Reschedule] [...]   │
├─────────────────────────────┤
│ 5:30 PM  [FB] Blog share    │
│ Status: Scheduled           │
│ [Edit] [Reschedule] [...]   │
├─────────────────────────────┤
│ [+ Add Post for This Day]   │
└─────────────────────────────┘

Data Sources

Data Source Location
Calendar posts calendarPosts data/seed.ts
Post details posts (joined by postId) data/seed.ts

Next Steps