Skip to content

Commit 16b44d4

Browse files
authored
Merge pull request #16 from objectql/copilot/implement-airtable-calendar-component
2 parents 6bba745 + 4f7d2ea commit 16b44d4

7 files changed

Lines changed: 934 additions & 1 deletion

File tree

apps/playground/src/data/examples.ts

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,93 @@ export const examples = {
638638
]
639639
}
640640
]
641+
}`,
642+
643+
// Calendar View - Airtable-style calendar
644+
'calendar-view': `{
645+
"type": "div",
646+
"className": "space-y-4",
647+
"body": [
648+
{
649+
"type": "div",
650+
"className": "space-y-2",
651+
"body": [
652+
{
653+
"type": "text",
654+
"content": "Calendar View",
655+
"className": "text-2xl font-bold"
656+
},
657+
{
658+
"type": "text",
659+
"content": "Airtable-style calendar for displaying records as events",
660+
"className": "text-muted-foreground"
661+
}
662+
]
663+
},
664+
{
665+
"type": "calendar-view",
666+
"className": "h-[600px] border rounded-lg",
667+
"view": "month",
668+
"titleField": "title",
669+
"startDateField": "start",
670+
"endDateField": "end",
671+
"colorField": "type",
672+
"colorMapping": {
673+
"meeting": "#3b82f6",
674+
"deadline": "#ef4444",
675+
"event": "#10b981",
676+
"holiday": "#8b5cf6"
677+
},
678+
"data": [
679+
{
680+
"id": 1,
681+
"title": "Team Standup",
682+
"start": "${new Date(new Date().setHours(9, 0, 0, 0)).toISOString()}",
683+
"end": "${new Date(new Date().setHours(9, 30, 0, 0)).toISOString()}",
684+
"type": "meeting",
685+
"allDay": false
686+
},
687+
{
688+
"id": 2,
689+
"title": "Project Launch",
690+
"start": "${new Date(new Date().setDate(new Date().getDate() + 3)).toISOString()}",
691+
"type": "deadline",
692+
"allDay": true
693+
},
694+
{
695+
"id": 3,
696+
"title": "Client Meeting",
697+
"start": "${new Date(new Date().setDate(new Date().getDate() + 5)).toISOString()}",
698+
"end": "${new Date(new Date(new Date().setDate(new Date().getDate() + 5)).setHours(14, 0, 0, 0)).toISOString()}",
699+
"type": "meeting",
700+
"allDay": false
701+
},
702+
{
703+
"id": 4,
704+
"title": "Team Building Event",
705+
"start": "${new Date(new Date().setDate(new Date().getDate() + 7)).toISOString()}",
706+
"end": "${new Date(new Date().setDate(new Date().getDate() + 9)).toISOString()}",
707+
"type": "event",
708+
"allDay": true
709+
},
710+
{
711+
"id": 5,
712+
"title": "Code Review",
713+
"start": "${new Date(new Date().setDate(new Date().getDate() + 1)).toISOString()}",
714+
"end": "${new Date(new Date(new Date().setDate(new Date().getDate() + 1)).setHours(15, 0, 0, 0)).toISOString()}",
715+
"type": "meeting",
716+
"allDay": false
717+
},
718+
{
719+
"id": 6,
720+
"title": "National Holiday",
721+
"start": "${new Date(new Date().setDate(new Date().getDate() + 10)).toISOString()}",
722+
"type": "holiday",
723+
"allDay": true
724+
}
725+
]
726+
}
727+
]
641728
}`
642729
};
643730

@@ -646,5 +733,6 @@ export type ExampleKey = keyof typeof examples;
646733
export const exampleCategories = {
647734
'Primitives': ['simple-page', 'input-states', 'button-variants'],
648735
'Layouts': ['grid-layout', 'dashboard', 'tabs-demo'],
649-
'Forms': ['form-demo']
736+
'Forms': ['form-demo'],
737+
'Data Display': ['calendar-view']
650738
};

docs/components/calendar-view.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Calendar View Component
2+
3+
The `calendar-view` component is an Airtable-style calendar for displaying records as events. It provides three view modes: Month, Week, and Day.
4+
5+
## Features
6+
7+
- **Multiple View Modes**: Switch between Month, Week, and Day views
8+
- **Flexible Data Mapping**: Map your data fields to event properties
9+
- **Color Coding**: Support for color-coded events with custom color mappings
10+
- **Interactive**: Click on events and dates (with callbacks)
11+
- **Responsive**: Works seamlessly on different screen sizes
12+
13+
## Basic Usage
14+
15+
```json
16+
{
17+
"type": "calendar-view",
18+
"data": [
19+
{
20+
"id": 1,
21+
"title": "Team Meeting",
22+
"start": "2026-01-13T10:00:00.000Z",
23+
"end": "2026-01-13T11:00:00.000Z",
24+
"color": "#3b82f6"
25+
}
26+
]
27+
}
28+
```
29+
30+
## Properties
31+
32+
| Property | Type | Default | Description |
33+
|:---|:---|:---|:---|
34+
| `data` | `array` | `[]` | Array of record objects to display as events |
35+
| `view` | `'month' \| 'week' \| 'day'` | `'month'` | Default view mode |
36+
| `titleField` | `string` | `'title'` | Field name to use for event title |
37+
| `startDateField` | `string` | `'start'` | Field name for event start date |
38+
| `endDateField` | `string` | `'end'` | Field name for event end date (optional) |
39+
| `allDayField` | `string` | `'allDay'` | Field name for all-day flag |
40+
| `colorField` | `string` | `'color'` | Field name for event color |
41+
| `colorMapping` | `object` | `{}` | Map field values to colors |
42+
| `allowCreate` | `boolean` | `false` | Allow creating events by clicking on dates |
43+
| `className` | `string` | - | Additional CSS classes |
44+
45+
## Data Structure
46+
47+
Each event object in the `data` array should have the following structure:
48+
49+
```typescript
50+
{
51+
id: string | number; // Unique identifier
52+
title: string; // Event title (or use custom titleField)
53+
start: string | Date; // Start date/time (ISO string or Date)
54+
end?: string | Date; // End date/time (optional)
55+
allDay?: boolean; // Whether it's an all-day event
56+
color?: string; // Event color (hex or CSS color)
57+
[key: string]: any; // Any other custom data
58+
}
59+
```
60+
61+
## Examples
62+
63+
### Month View with Color Mapping
64+
65+
```json
66+
{
67+
"type": "calendar-view",
68+
"className": "h-[600px] border rounded-lg",
69+
"view": "month",
70+
"colorField": "type",
71+
"colorMapping": {
72+
"meeting": "#3b82f6",
73+
"deadline": "#ef4444",
74+
"event": "#10b981"
75+
},
76+
"data": [
77+
{
78+
"id": 1,
79+
"title": "Team Standup",
80+
"start": "2026-01-13T09:00:00.000Z",
81+
"end": "2026-01-13T09:30:00.000Z",
82+
"type": "meeting"
83+
},
84+
{
85+
"id": 2,
86+
"title": "Project Deadline",
87+
"start": "2026-01-20T00:00:00.000Z",
88+
"type": "deadline",
89+
"allDay": true
90+
}
91+
]
92+
}
93+
```
94+
95+
## View Modes
96+
97+
### Month View
98+
Displays a full month calendar grid with events shown as colored bars on their respective dates. Perfect for getting a high-level overview of the month.
99+
100+
### Week View
101+
Shows a week at a time with each day in a column. Events display with their times, ideal for detailed weekly planning.
102+
103+
### Day View
104+
Displays a single day with hourly time slots from 12 AM to 11 PM. Events are positioned at their scheduled times, great for detailed daily schedules.
105+
106+
## Events & Callbacks
107+
108+
The calendar view supports several event callbacks through the `onAction` mechanism:
109+
110+
- `event_click`: Triggered when an event is clicked
111+
- `date_click`: Triggered when a date cell is clicked
112+
- `view_change`: Triggered when the view mode changes
113+
- `navigate`: Triggered when navigating between dates
114+
115+
## Styling
116+
117+
The calendar view is fully styled with Tailwind CSS and supports custom styling through the `className` prop.
118+
119+
## Integration with ObjectQL
120+
121+
When used with ObjectQL, the calendar view can automatically fetch and display records from your database.

docs/spec/component-library.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Components for visualizing data.
6868
| `alert` | Highlighted message | `variant`, `title`, `description` |
6969
| `table` | Data-driven table | `columns`, `data`, `caption`, `footer` |
7070
| `carousel` | Slideshow component | `items`, `orientation`, `showArrows` |
71+
| `calendar-view` | Airtable-style calendar | `data`, `view`, `titleField`, `startDateField`, `endDateField`, `colorField` |
7172

7273
## 6. Feedback Components
7374
Indicators for system status or feedback.

0 commit comments

Comments
 (0)