Files
deardiary/todo/calendar.md
lotherk 0bdd71a4ed feat: v0.1.0 - geolocation capture, calendar, search, Starlight docs site
- Automatic browser geolocation capture on event creation
- Reverse geocoding via Nominatim API for place names
- Full-text search with SQLite FTS5
- Calendar view for browsing past entries
- DateNavigator component for day navigation
- SearchModal with Ctrl+K shortcut
- QuickAddWidget with Ctrl+J shortcut
- Starlight documentation site with GitHub Pages deployment
- Multiple AI provider support (Groq, OpenAI, Anthropic, Ollama, LM Studio)
- Multi-user registration support

BREAKING: Events now include latitude/longitude/placeName fields
2026-03-27 02:27:55 +00:00

328 lines
8.8 KiB
Markdown

# Calendar View Feature Research
## Overview
This document outlines research and implementation ideas for adding a calendar view to DearDiary, enabling users to visualize their journaling activity across days, weeks, and months at a glance.
## Current State Analysis
### Existing Navigation & Data Flow
- **Routes**: `/` (Dashboard), `/today`, `/history`, `/diary`, `/day/:date`, `/journal/:date`, `/settings`
- **API**: `getDays()` returns `Array<{ date, eventCount, hasJournal, journalTitle?, journalExcerpt? }>`
- **History page**: Currently a simple list showing all days chronologically
### Key Data Points Per Day
- `date`: ISO date string (YYYY-MM-DD)
- `eventCount`: Number of events captured
- `hasJournal`: Whether diary page has been generated
- `journalTitle`: Title from AI-generated diary
- `journalExcerpt`: Preview text from diary content
---
## Feature Description
### 1. Monthly Calendar View
**Primary use case**: Overview of journaling activity at a glance
- Grid layout (7 columns for weekdays)
- Each day cell shows:
- Date number
- Visual indicator(s) for presence of events/diary
- Event count (optional, on hover or expanded)
**Visual Indicators**
| State | Indicator |
|-------|-----------|
| No events | Empty cell, muted styling |
| Events only (draft) | Small blue/gray dot |
| Diary generated | Small purple dot |
| Both (events + diary) | Two dots or colored dot with indicator |
| Today | Highlighted cell (border/background) |
| Selected day | Different background/border |
**Event Density Visualization**
- Option to show density heat map (more events = darker shade)
- Scale: 1-2 events (light), 3-5 (medium), 6+ (dark)
### 2. Weekly Calendar View
**Primary use case**: Detailed look at recent activity
- Horizontal 7-day strip
- Each day shows expanded content:
- Event count
- Mini event list (first 2-3 events)
- Diary status badge
### 3. Daily Mini Calendar
- Fixed position in header or sidebar
- Shows current month
- Click to navigate to specific date
- Quick navigation (prev/next month arrows)
---
## UI Component Suggestions
### Recommended Libraries
| Library | Pros | Cons |
|---------|------|------|
| **react-big-calendar** | Full-featured, customizable, well-maintained | Requires styling, may be heavy |
| **react-calendar** | Lightweight, simple API, good theming | Limited customization |
| **react-datepicker** | Easy to integrate, accessible | More input-focused than display |
| **fullcalendar-react** | Enterprise-grade, many views | Complex, may be overkill |
| **Custom CSS Grid** | Full control, lightweight | More implementation work |
### Recommendation: Custom CSS Grid + react-calendar hybrid
For DearDiary's needs, a custom implementation using CSS Grid provides:
- Full Tailwind integration (matches existing style)
- Lightweight bundle
- Complete control over visual indicators
- No dependency on heavy calendar libraries
**Fallback**: If ready-made needed, `react-calendar` is lightweight (~50KB) and sufficient for monthly view.
### Tailwind CSS Implementation (Custom)
```tsx
// Monthly calendar grid
<div className="grid grid-cols-7 gap-1">
{days.map(day => (
<button className={cn(
"relative p-2 rounded-lg text-center",
day.isToday && "ring-2 ring-purple-500",
day.hasEvents && "bg-slate-800",
day.hasJournal && "bg-purple-900/30"
)}>
<span>{day.dateNumber}</span>
{day.hasEvents && (
<span className="absolute bottom-1 left-1/2 -translate-x-1/2 w-1.5 h-1.5 rounded-full bg-blue-400" />
)}
</button>
))}
</div>
```
---
## Integration with Existing Pages
### 1. Standalone Calendar Page (`/calendar`)
New route added to App.tsx:
- Full monthly calendar view
- Navigation to previous/next months
- Click on day navigates to `/day/:date` or `/journal/:date`
- Toggle between month/week views
### 2. Integration with Dashboard
Replace or supplement "Recent Diary Pages" with mini calendar:
- Show current month
- Click date to navigate
- Compact version (fewer details per cell)
### 3. Integration with History Page
Replace list view with calendar as default:
- Toggle between calendar and list views
- Calendar shows activity overview
- List remains available for detailed browsing
### 4. Navigation Updates
Update Navbar to include calendar link:
```tsx
// App.tsx Navbar
<a href="/calendar" className="text-slate-300 hover:text-white transition">Calendar</a>
```
### 5. Quick Date Navigation
Mini calendar in header (optional):
- Always visible month view
- Click date = navigate to `/day/:date`
---
## Implementation Complexity
### Phase 1: Basic Monthly Calendar (Priority: High)
- [ ] Create `Calendar.tsx` component
- [ ] Add `/calendar` route
- [ ] Fetch days data for current month
- [ ] Render grid with visual indicators
- [ ] Click to navigate
**Complexity**: ~2-3 hours
**Files**: `frontend/src/components/Calendar.tsx`, route in App.tsx
### Phase 2: Dashboard Integration (Priority: Medium)
- [ ] Add mini calendar to Dashboard
- [ ] Show current month
- [ ] Click date navigates to day
**Complexity**: ~1-2 hours
### Phase 3: Week View (Priority: Low)
- [ ] Add week view toggle
- [ ] Horizontal 7-day strip
- [ ] Expanded content per day
**Complexity**: ~2-3 hours
### Phase 4: Advanced Features (Priority: Low)
- [ ] Event density heat map
- [ ] Drag to select date range
- [ ] Export calendar as image
- [ ] iCal integration
**Complexity**: Varies
---
## API Requirements
### Current API Sufficiency
`getDays()` returns all days - filtering by month happens on client. For larger datasets:
**Potential enhancement**:
```typescript
// Get days for specific month (optional optimization)
async getDaysByMonth(year: number, month: number): Promise<DayInfo[]>
```
**Current workaround sufficient**: Fetch all days, filter in React (acceptable for < 365 entries).
---
## Accessibility Considerations
### WCAG 2.1 AA Compliance
1. **Keyboard Navigation**
- Arrow keys to move between days
- Enter/Space to select
- Escape to close calendar
2. **Screen Reader Support**
- `aria-label` on each day cell: "March 15, 2026 - 3 events, diary generated"
- `aria-current` for today
- `role="grid"` with proper row/cell structure
3. **Visual Indicators**
- Don't rely solely on color
- Use icons/shapes + color
- Sufficient contrast ratios (4.5:1 minimum)
4. **Focus Management**
- Focus visible on calendar open
- Return focus to trigger element on close
### Example ARIA Implementation
```tsx
<button
aria-label={`${dateString} - ${eventCount} events${hasJournal ? ', diary generated' : ''}`}
aria-current={isToday ? 'date' : undefined}
className="..."
>
<span aria-hidden="true">{dayNumber}</span>
{hasEvents && <span className="sr-only">Has events</span>}
</button>
```
---
## Mobile-Friendly Considerations
### Responsive Design
1. **Viewport Adaptation**
- Desktop: Full monthly grid (35 cells visible)
- Tablet: Scrollable or condensed
- Mobile: Week view default, swipe between weeks
2. **Touch Targets**
- Minimum 44x44px tap targets
- Adequate spacing between dates
3. **Interaction Patterns**
- Swipe left/right for month navigation
- Tap to select, long-press for context menu
### Library Considerations
If using `react-big-calendar`:
```tsx
<Calendar
views={['month', 'week', 'day']}
defaultView="week" // Default to week on mobile
popup
selectable
style={{ height: 'auto' }}
/>
```
---
## Recommended Implementation Plan
### Priority 1: Calendar Page
1. Create `frontend/src/components/Calendar.tsx`
- Monthly grid using CSS Grid
- Visual dots for event/diary status
- Click navigates to `/day/:date`
2. Add route `/calendar` in App.tsx
3. Add nav link in Navbar
4. Test with existing data
### Priority 2: Dashboard Integration
1. Add mini calendar above recent entries
2. Show current month
3. Highlight today, clickable dates
### Priority 3: History Enhancement
1. Add toggle between list/calendar views
2. Calendar as default
### Priority 4: Week View (Optional)
1. Add view switcher
2. Horizontal week strip with event previews
---
## Summary
| Aspect | Recommendation |
|--------|----------------|
| **Implementation** | Custom CSS Grid (Tailwind) |
| **First placement** | New `/calendar` page |
| **View types** | Monthly default, week as secondary |
| **Indicators** | Dots (blue=events, purple=diary) |
| **Navigation** | Click to `/day/:date` or `/journal/:date` |
| **Accessibility** | Full ARIA, keyboard nav |
| **Mobile** | Default to week view, touch-friendly |
### Estimated Timeline
- Phase 1 (Calendar page): 2-3 hours
- Phase 2 (Dashboard): 1-2 hours
- Phase 3 (Week view): 2-3 hours
- **Total**: ~5-8 hours
---
## Questions for Further Research
1. Should calendar support date range selection for bulk operations?
2. Export to iCal/Google Calendar desired?
3. Sync with external calendars (Google, Apple)?
4. Recurring event support?
5. Need to show time-of-day heat map?